home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / devs / new8n1 / 8n1_030.s < prev    next >
Text File  |  1980-12-01  |  67KB  |  2,177 lines

  1. ********************************************************************************
  2. **                                          **
  3. **  Name       : 8n1_030.s                              **
  4. **  Copyright  : © Copyright 96-97                          **
  5. **  Author     : Iain Barclay                              **
  6. **  Created    : 15 Jul 97                              **
  7. **  Version    : 43.3                                  **
  8. **                                          **
  9. ********************************************************************************
  10.      ;
  11.      ;      SNMA specific options
  12.      ;
  13.      IFD      SNMA
  14.      ;
  15.      CPU      M68030
  16.      ;
  17.      SNMAOPT  Q,A,M,T,E-,P,R,B
  18.      ;
  19.      ELSE
  20.      ; I have phxopts define this symbol
  21.      IFD PHXASS
  22.      machine 68030
  23.      ENDC
  24.      ENDC
  25.      ;
  26.      ;
  27. NEWCODE  SET      1    ; Set to 1 to use Newcode
  28. SETDSR     SET      0    ; Set to 1 to set DSR always
  29. NCOMM     SET      0    ; Set to 1 for use with NComm
  30. STATS     SET      0    ; Set to 1 to output stats for debugging
  31. FASTVBR  SET      1    ; Set to 1 to enable moving of VBR to fastram
  32. DANGER     SET      0    ; Set to 1 to enable dangerous code
  33. NEGCHECK SET      1    ; Set to 1 to enable -1 size check
  34. EOFCODE  SET      1    ; Set to 1 to include EOF code
  35.      ;
  36.      ;
  37.      ;
  38.      SECTION  text,CODE
  39.      ;
  40.      ;
  41.      ;
  42. DEVICES_SERIAL_I_OBSOLETE  EQU        1
  43.      ;
  44.      ;
  45.      ;
  46.      INCLUDE  "exec/lists.i"
  47.      INCLUDE  "exec/memory.i"
  48.      INCLUDE  "exec/resident.i"
  49.      INCLUDE  "exec/devices.i"
  50.      INCLUDE  "exec/execbase.i"
  51.      INCLUDE  "exec/io.i"
  52.      INCLUDE  "exec/ports.i"
  53.      INCLUDE  "exec/errors.i"
  54.      INCLUDE  "exec/initializers.i"
  55.      INCLUDE  "intuition/preferences.i"
  56.      INCLUDE  "devices/timer.i"
  57.      INCLUDE  "devices/serial.i"
  58.      INCLUDE  "hardware/custom.i"
  59.      INCLUDE  "hardware/cia.i"
  60.      INCLUDE  "hardware/intbits.i"
  61.      INCLUDE  "hardware/adkbits.i"
  62.      INCLUDE  "resources/misc.i"
  63.      INCLUDE  "exec/alerts.i"
  64.      INCLUDE  "exec/macros.i"
  65.      INCLUDE  "8n1.device_rev.i"
  66.      ;
  67.      ;      Define hardware references
  68.      ;
  69.      XREF      _custom
  70.      XREF      _intena,_intenar,_intreq,_intreqr
  71.      XREF      _ciab,_ciabpra
  72.      XREF      _serper,_serdat,_serdatr
  73.      XREF      _adkcon,_adkconr
  74.      ;
  75.      ;      Exec Functions
  76.      ;
  77.      XREF      _LVORemDevice,_LVOOpenDevice,_LVOCloseDevice
  78.      XREF      _LVOSupervisor
  79.      XREF      _LVOAllocMem,_LVOFreeMem,_LVOCopyMem,_LVOTypeOfMem
  80.      XREF      _LVOReplyMsg
  81.      XREF      _LVOSendIO,_LVOAbortIO
  82.      XREF      _LVODisable,_LVOEnable
  83.      XREF      _LVOFindName
  84.      XREF      _LVOOpenResource
  85.      XREF      _LVOAddIntServer,_LVORemIntServer
  86.      XREF      _LVOAlert
  87.      XREF      _LVOOpenLibrary,_LVOCloseLibrary
  88.      XREF      _LVOCacheClearU
  89.      ;
  90.      ;      Misc Resource Functions
  91.      ;
  92.      XREF      _LVOAllocMiscResource,_LVOFreeMiscResource
  93.      ;
  94.      ;      Intuition Functions
  95.      ;
  96.      XREF      _LVOGetPrefs
  97.      ;
  98.      ;      Mask used to get rid of the printer bits.
  99.      ;
  100. PRTMASK  EQU      (CIAF_PRTRPOUT|CIAF_PRTRBUSY)
  101.      ;
  102.      ;      Autovector offsets
  103.      ;
  104. LVL1VEC  EQU      (1-1)*4+$64
  105. LVL5VEC  EQU      (5-1)*4+$64
  106. VBR_SIZE EQU      $400
  107. custom     EQU      $dff000
  108. ciab     EQU      $bfd000
  109.      ;
  110.      ;  New Style device stuff (not the best way but it will have too do for now)
  111.      ;  If u don't have New Style stuff defined elsewhere remove these ;
  112. ;NSCMD_DEVICEQUERY   EQU $4000
  113. ; STRUCTURE  NSDEVICEQUERYRESULT,0
  114. ;    ULONG   DEVQUERYFORMAT
  115. ;    ULONG   SIZEAVAILABLE
  116. ;    UWORD   DEVICETYPE
  117. ;    UWORD   DEVICESUBTYPE
  118. ;    APTR    SUPPORTEDCOMMANDS
  119. ;    LABEL   NSDEVICEQUERYRESULT_SIZE
  120. ;NSDEVTYPE_SERIAL     EQU 11
  121.      ;
  122.      ;      Device base
  123.      ;      longword aligned
  124.      ;
  125.      STRUCTURE Base8n1,LIB_SIZE
  126.      UBYTE      vb_pad1
  127.      UBYTE      vb_pad2
  128.      ULONG      vb_SaveDDRA
  129.      ULONG      vb_SavePRA
  130.      APTR      vb_MiscBase
  131.      APTR      vb_OldLevel1
  132.      APTR      vb_OldLevel5
  133.      ULONG      vb_SegList
  134.      ULONG      vb_DefBaud
  135.      ULONG      vb_DefRBufLen
  136.      ULONG      vb_CurRBuf
  137.      ULONG      vb_CurRBufLen
  138.      ULONG      vb_CurBaud
  139.      ULONG      vb_SerFlags
  140.      ULONG      vb_Initialized
  141.      LABEL      sizeof_Base8n1
  142.      ;
  143.      ;
  144.      ;
  145.     IFNE STATS
  146.      XREF      _KPrintF
  147.      XREF      KPrintF
  148.     ENDC
  149.      ;
  150.      ;
  151.      ;
  152. Start:
  153.      moveq      #-1,d0                  ; set return code
  154.      rts                          ; return
  155.      ;
  156.      ;      RamLib looks for this romtag
  157.      ;
  158. ROMTag     DC.W      RTC_MATCHWORD               ; RT_MATCHWORD
  159.      DC.L      ROMTag                  ; RT_MATCHTAG
  160.      DC.L      ENDTag                  ; RT_ENDSKIP
  161.      DC.B      RTF_AUTOINIT                  ; RT_FLAGS
  162.      DC.B      VERSION                  ; RT_VERSION
  163.      DC.B      NT_DEVICE                  ; RT_TYPE
  164.      DC.B      0                      ; RT_PRI
  165.      DC.L      Name                      ; RT_NAME
  166.      DC.L      IdString                  ; RT_IDSTRING
  167.      DC.L      Init                      ; RT_INIT
  168.      ;
  169.      ;      Perform device initialization
  170.      ;
  171.     cnop 0,4    ; align for 020+
  172. InitRoutine:
  173.      exg      d0,a0                   ; swap seglist and base
  174.      move.l   d0,vb_SegList(a0)              ; store seglist in base
  175.      move.l   a6,SysBase                  ; store in global storage
  176.      exg      a0,d0                   ; swap them back
  177.      rts                          ; return
  178.      ;
  179.      ;
  180.      ;
  181.     cnop 0,4 ; align for 020+
  182. dev_Open:   ; (a1 iorequest, a5 will be Base8n1, a6 sysbase )
  183.      addq.w   #1,LIB_OPENCNT(a6)              ; fake open so device is not expunged
  184.      move.l   a5,-(sp)                  ; save registers
  185.      move.l   a6,a5                   ; save base
  186.      ;
  187.      cmpi.w   #IOEXTSER_SIZE,MN_LENGTH(a1)          ; IORequest size >= IOEXTSER_SIZE (2+4)
  188.      bcs      50$                      ; nope, finish
  189.      ;
  190.      tst.l      d0                      ; unit 0 specified?
  191.      bne      50$                      ; nope, error (who cares?)
  192.      ;
  193.      cmpi.w   #1,LIB_OPENCNT(a5)              ; currently open?
  194.      bne      10$                      ; yep, go process
  195.      ;
  196.      move.l   IO_READLEN(a1),vb_SerFlags(a5)      ; save flags
  197.      ;
  198.      tst.l      vb_Initialized(a5)              ; already initialized?
  199.      bne      40$                      ; yep, skip initialization
  200.      ;
  201.      move.l   SysBase(pc),a6              ; get ExecBase
  202.      move.l   a1,-(sp)                  ; save register
  203.      ;
  204.      lea      miscresource(pc),a1              ; ptr to resource name
  205.      jsr      _LVOOpenResource(a6)              ; go open it
  206.      move.l   d0,vb_MiscBase(a5)              ; save base
  207.      ;
  208.      moveq      #MR_SERIALPORT,d0              ; set unit number
  209.      bsr      allocResource               ; go allocate it
  210.      tst.l      d0                      ; did we get it?
  211.      bne.b      20$                      ; nope, error
  212.      ;
  213.      moveq      #MR_SERIALBITS,d0              ; set unit number
  214.      bsr      allocResource               ; go allocate it
  215.      tst.l      d0                      ; did we get it?
  216.      bne.b      5$                      ; nope, error
  217.      ;
  218.      ;      Get system preferences
  219.      ;
  220.      lea      intuitlib(pc),a1              ; ptr to library name
  221.      moveq      #0,d0                   ; can't use OldOpenLibrary as this will not be supported.
  222.      jsr      _LVOOpenLibrary(a6)              ; go open it (any version)
  223.      move.l   d0,a6                   ; get intuition base
  224.      ;
  225.      move.l   #(pf_SerParShk+3)&$fffffffc,d0      ; size we need (aligned)
  226.      suba.l   d0,sp                   ; reserve space
  227.      ;
  228.      move.l   sp,a0                   ; set data area ptr
  229.      jsr      _LVOGetPrefs(a6)              ; get preferences
  230.      ;
  231.      move.l   a6,a1                   ; get intuition base
  232.      move.l   SysBase(pc),a6              ; restore ExecBase
  233.      jsr      _LVOCloseLibrary(a6)              ; close it
  234.      ;
  235.      moveq      #$0f,d0                  ; set mask
  236.      and.b      pf_SerStopBuf(sp),d0              ; get bufsize index
  237.      moveq      #0,d1                   ; clear upper half
  238.      addq.l   #8,d0                   ; calc shift value
  239.      move.w   pf_BaudRate(sp),d1              ; get baud rate
  240.      lsl.l      #2,d0                   ; get default bufsize
  241.      move.l   d0,vb_DefRBufLen(a5)              ; and store
  242.     IFNE NEWCODE
  243.      move.l   .baudTable(pc,d1.l*4),d1          ; get baud rate
  244.     ELSE
  245.      move.w   .baudTable(pc,d1.l*2),d1          ; get baud rate
  246.     ENDC
  247.      ;
  248.      move.l   d1,vb_DefBaud(a5)              ; and store
  249.      ;
  250.      bsr      internalReset               ; go init baud and buffer
  251.      ;
  252.      lea      (pf_SerParShk+3)&$fffffffc(sp),sp   ; restore stack
  253.      tst.l      d0                      ; got 'em?
  254.      beq.b      30$                      ; yep, branch
  255.      ;
  256.      moveq      #MR_SERIALBITS,d0              ; set unit
  257.      move.l   vb_MiscBase(a5),a6              ; get MiscBase
  258.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  259.      ;
  260. 5$     moveq      #MR_SERIALPORT,d0              ; set unit
  261.      move.l   vb_MiscBase(a5),a6              ; get MiscBase
  262.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  263.      ;
  264. 20$     moveq      #SerErr_DevBusy,d0              ; set error status
  265.      move.l   (sp)+,a1                  ; restore registers
  266.      bra      50$                      ; go return
  267.      ;
  268.      ;      Preferences baud lookup table
  269.      ;
  270.      cnop 0,4 ; align for 020+
  271.     IFNE NEWCODE
  272. .baudTable:
  273.      dc.l      112,300,1200,2400,4800,9600,19200,31250,38400,57600,62400,64800
  274.      dc.l      76800,115200
  275.     ELSE
  276. .baudTable:
  277.      dc.w      112,300,1200,2400,4800,9600,19200,31250,38400,57600,62400,64800
  278.     ENDC
  279.      ;
  280.      cnop 0,4 ; align for 020+
  281. 30$     moveq      #0,d1                   ; clear flags
  282.      lea      timerReq(pc),a1              ; ptr to timer request
  283.      moveq      #UNIT_VBLANK,d0              ; set unit
  284.      lea      timerdevice(pc),a0              ; ptr to device name
  285.      jsr      _LVOOpenDevice(a6)              ; go open it
  286.      ;
  287.     IFNE DANGER
  288.      move.w   #$04000,_intena
  289.      addq.b   #1,IDNestCnt(a6)              ; disable interrupts
  290.     ELSE
  291.      jsr      _LVODisable(a6)              ; disable interrupts
  292.     ENDC
  293.      ;
  294.      move.l   #ciab,a1                  ; get ptr to ciab
  295.      move.b   ciaddra(a1),d0
  296.      move.l   d0,vb_SaveDDRA(a5)              ; save DDR value
  297.      andi.b   #PRTMASK,d0                  ; make serial bits input
  298.      move.b   (a1),d1                  ; ciapra(a1)
  299.      ori.b      #CIAF_COMDTR|CIAF_COMRTS,d0          ; make DTR/RTS output
  300.      move.l   d1,vb_SavePRA(a5)              ; save PR value
  301.      andi.b   #CIAF_COMDTR|CIAF_COMRTS|PRTMASK,d0 ; turn on DTR/RTS
  302.      move.b   d0,ciaddra(a1)
  303.      andi.b   #CIAF_COMCTS|CIAF_COMDSR|PRTMASK,d1 ; make CTS/DSR input
  304.      move.b   d1,(a1)                  ; ciapra(a1)
  305.      ;
  306.      moveq      #INTB_PORTS,d0              ; get interrupt number
  307.      lea      VBInterrupt(pc),a1              ; get interrupt ptr
  308.      jsr      _LVOAddIntServer(a6)              ; add it to the list
  309.      ;
  310.      bsr      getVBR                  ; get vector base (in A0)
  311.      ;
  312.     IFNE FASTVBR
  313.      move.l   a5,-(sp)                  ; save a5
  314.      move.l   a0,-(sp)                  ; save VBR
  315.      move.l   a0,a1
  316.      jsr      _LVOTypeOfMem(a6)
  317.      btst      #MEMB_FAST,d0               ; VBR in fast?
  318.      bne.b      nofast$                  ; yep, branch
  319.      move.l   #VBR_SIZE,d0
  320.      moveq      #MEMF_PUBLIC|MEMF_FAST,d1
  321.      jsr      _LVOAllocMem(a6)              ; Alloc fast-ram for VBR
  322.      tst.l      d0
  323.      beq.b      nofast$                  ; no fast, branch
  324.      move.l   (sp),a0                  ; get VBR
  325.      move.l   d0,a1
  326.      move.l   d0,-(sp)                  ; save new VBR
  327.      move.l   #VBR_SIZE,d0
  328.      jsr      _LVOCopyMem(a6)
  329.      move.l   (sp)+,a0                  ; get new VBR
  330.      lea      setVBR$(pc),a5
  331.      jsr      _LVOSupervisor(a6)              ; set new VBR
  332.      jsr      _LVOCacheClearU(a6)              ; clear cache
  333.      move.l   (sp)+,d0                  ; was old VBR zero?
  334.      beq.b      waszero$                  ; yep, branch (don't free)
  335.      move.l   d0,a1
  336.      move.l   #VBR_SIZE,d0
  337.      jsr      _LVOFreeMem(a6)
  338. waszero$
  339.      bsr      getVBR
  340.      bra.b      vbend$
  341.      cnop      0,4
  342. setVBR$
  343.      movec      a0,vbr                  ; set VBR
  344.      rte
  345.      cnop      0,4
  346. nofast$
  347.      move.l   (sp)+,a0                  ; restore VBR
  348. vbend$
  349.      move.l   (sp)+,a5                  ; restore a5
  350.     ENDC
  351.      move.l   LVL1VEC(a0),vb_OldLevel1(a5)          ; save original vector
  352.      lea      level1(pc),a1               ; get new vector ptr
  353.      move.l   a1,LVL1VEC(a0)              ; set new vector
  354.      ;
  355.      move.l   LVL5VEC(a0),vb_OldLevel5(a5)          ; save original vector
  356.      lea      level5(pc),a1               ; get new vector ptr
  357.      move.l   a1,LVL5VEC(a0)              ; set new vector
  358.      ;
  359.      move.l   #custom+intena,a1              ; get ptr to custom chips
  360.      move.w   #INTF_RBF|INTF_TBE,intreq-intena(a1); clear pending interrupts
  361.      move.w   #INTF_SETCLR|INTF_RBF|INTF_TBE,(a1) ; enable RBF & TBE
  362.      ;
  363.      addq.l   #1,vb_Initialized(a5)           ; set flag
  364.      ;
  365.     IFNE DANGER
  366.      subq.b   #1,IDNestCnt(a6)
  367.      bge.b      enable$
  368.      move.w   #$0C000,(a1)                  ; enable interrupts
  369. enable$
  370.     ELSE
  371.      jsr      _LVOEnable(a6)              ; enable interrupts
  372.     ENDC
  373.      ;
  374.      move.l   (sp)+,a1                  ; restore register
  375.      ;
  376.      bra.b      40$                      ; go exit
  377.      ;
  378.      cnop 0,4 ; align for 020+
  379. 10$     moveq      #SerErr_DevBusy,d0              ; preset error status
  380.      btst      #SERB_SHARED,vb_SerFlags+3(a5)      ; opened shared?
  381.      beq.b      50$                      ; nope, error
  382.      btst      #SERB_SHARED,IO_SERFLAGS(a1)          ; requesting shared?
  383.      beq.b      50$                      ; nope, error
  384.      ;
  385.      ;      Initialize I/O request
  386.      ;
  387. 40$     moveq      #8,d0                   ; get char size
  388.      move.b   d0,IO_READLEN(a1)              ; set read length
  389.      move.b   d0,IO_WRITELEN(a1)              ; set write length
  390.      moveq      #1,d0                   ; get stop bits
  391.      move.b   d0,IO_STOPBITS(a1)              ; set stop bits
  392.      move.b   IO_SERFLAGS(a1),d0
  393.      ori.b      #SERF_XDISABLED|SERF_RAD_BOOGIE|SERF_QUEUEDBRK|SERF_7WIRE,d0 ;flags
  394.      andi.b   #~(SERF_PARTY_ODD|SERF_PARTY_ON),d0 ; not used
  395.      move.b   d0,IO_SERFLAGS(a1)
  396.      move.l   vb_CurBaud(a5),IO_BAUD(a1)          ; set baud
  397.      moveq      #0,d0                   ; no error
  398.      move.l   vb_CurRBufLen(a5),IO_RBUFLEN(a1)    ; set read buffer length
  399.      ;
  400.      addq.w   #1,LIB_OPENCNT(a5)              ; incr open count
  401.      andi.b   #~(1<<LIBB_DELEXP),LIB_FLAGS(a5)    ; clear expunge bit
  402.      ;
  403. 50$     move.b   d0,IO_ERROR(a1)              ; store error code
  404.      move.l   a5,a6                   ; restore base
  405.      move.l   (sp)+,a5                  ; restore registers
  406.      subq.w   #1,LIB_OPENCNT(a6)              ; remove fake open
  407.      rts                          ; return
  408.      ;
  409.      ;      Attempt to allocate one of the serial resources.
  410.      ;
  411.      cnop 0,4 ; align for 020+
  412. allocResource:
  413.      move.l   a6,-(sp)                  ; save base pointer
  414.      move.l   d0,-(sp)                  ; save unit
  415.      lea      Name(pc),a1                  ; get lock name
  416.      move.l   vb_MiscBase(a5),a6              ; get MiscBase
  417.      jsr      _LVOAllocMiscResource(a6)          ; go allocate it
  418.      tst.l      d0                      ; did we get it?
  419.      beq.b      20$                      ; yep, branch
  420.      ;
  421.      ;      It's in use, so we try to locate the device using the string
  422.      ;      returned and attempt to remove it.
  423.      ;
  424.      move.l   SysBase(pc),a6              ; get ExecBase
  425.      ;
  426.      move.l   d0,a1                   ; get ptr to serial name
  427.      lea      DeviceList(a6),a0              ; get ptr to device list
  428.      jsr      _LVOFindName(a6)              ; go find it
  429.      tst.l      d0                      ; found?
  430.      beq.b      10$                      ; nope, branch
  431.      ;
  432.      move.l   d0,a1                   ; xfer device ptr
  433.      jsr      _LVORemDevice(a6)              ; remove it
  434.      ;
  435.      ;      We then retry the allocate.
  436.      ;
  437. 10$     move.l   (sp),d0                  ; get unit
  438.      lea      Name(pc),a1                  ; get lock name
  439.      move.l   vb_MiscBase(a5),a6              ; get MiscBase
  440.      jsr      _LVOAllocMiscResource(a6)          ; go allocate it
  441.      ;
  442. 20$     addq.l   #4,sp                   ; restore stack ptr
  443.      move.l   (sp)+,a6                  ; restore base ptr
  444.      rts                          ; return
  445.      ;
  446.      ;      Set exception vectors
  447.      ;
  448.      cnop 0,4 ; align for 020+
  449. getVBR:
  450.      move.l   a5,-(sp)                  ; save registers
  451.      lea      10$(pc),a5                  ; ptr to routine
  452.      jsr      _LVOSupervisor(a6)              ; get into supervisor state
  453.      move.l   (sp)+,a5                  ; restore register
  454.      rts                          ; return
  455.      cnop      0,4
  456. 10$     movec.l  vbr,a0                  ; get vector base
  457.      rte                          ; return
  458.      ;
  459.      ;      Device Close routine
  460.      ;
  461.      cnop 0,4 ; align for 020+
  462. dev_Close:
  463.      ;
  464.      moveq      #-1,d0                  ; invalidate
  465.      move.l   d0,IO_DEVICE(a1)              ;   device
  466.      ;
  467.      tst.w      LIB_OPENCNT(a6)              ; check we are open
  468.      beq.b      5$                      ; nope, branch
  469.      subq.w   #1,LIB_OPENCNT(a6)              ; decr open count
  470.      bne      dev_Null                  ; still open? yep, branch
  471. 5$
  472.      ;
  473.      move.l   a5,-(sp)                  ; save registers
  474.      move.l   a6,a5                   ; save base
  475.      move.l   SysBase(pc),a6              ; get ExecBase
  476.      ;
  477.      move.l   a1,-(sp)                  ; save registers
  478.      ;
  479.      bsr.b      getVBR                  ; get vector base (in A0)
  480.      ;
  481.      moveq      #1,d0                   ; set not restored code
  482.      ;
  483.      lea      level1(pc),a1               ; get our vector ptr
  484.      cmpa.l   LVL1VEC(a0),a1              ; do they match?
  485.      bne      10$                      ; nope, can't restore
  486.      ;
  487.      lea      level5(pc),a1               ; get our vector ptr
  488.      cmpa.l   LVL5VEC(a0),a1              ; do they match?
  489.      bne      10$                      ; nope, can't restore
  490.      ;
  491.     IFNE DANGER
  492.      move.w   #$04000,_intena
  493.      addq.b   #1,IDNestCnt(a6)              ; disabel interrupts
  494.     ELSE
  495.      jsr      _LVODisable(a6)              ; disable interrupts
  496.     ENDC
  497.      ;
  498.      move.l   vb_OldLevel1(a5),LVL1VEC(a0)          ; restore original vector
  499.      move.l   vb_OldLevel5(a5),LVL5VEC(a0)          ; restore original vector
  500.      ;
  501.      moveq      #INTB_PORTS,d0              ; get interrupt number
  502.      lea      VBInterrupt(pc),a1              ; get interrupt ptr
  503.      jsr      _LVORemIntServer(a6)              ; remove it from the list
  504.      ;
  505.      move.l   #custom+intena,a0              ; get custom base
  506.      move.w   #INTF_RBF|INTF_TBE,d0           ; indicate serial interrupts
  507.      move.w   d0,(a0)                  ; disable interrupts
  508.      move.w   d0,intreq-intena(a0)              ; clear pending interrupts
  509.      ;
  510.      bsr      freeBuf                  ; free allocated buffers
  511.      ;
  512.      move.l   #ciab,a0                  ; get pointer to ciab
  513.      move.b   ciaddra(a0),d0              ; get DDR value
  514.      andi.b   #PRTMASK,d0                  ; save printer bits
  515.      ori.b      #~PRTMASK,d0                  ; set serial bits to output
  516.      move.b   d0,ciaddra(a0)              ; store value
  517.      ;
  518.      move.b   (a0),d0                  ; get PR value ( ciapra(a0) )
  519.      andi.b   #PRTMASK,d0                  ; mask out serial bits
  520.      move.l   vb_SavePRA(a5),d1              ; get saved value
  521.      andi.b   #~PRTMASK,d1                  ; mask out printer bits
  522.      or.b      d1,d0                   ; combine the two
  523.      move.b   d0,(a0)                  ; and store ( ciapra(a0) )
  524.      ;
  525.      move.b   ciaddra(a0),d0              ; get DDR value
  526.      andi.b   #PRTMASK,d0                  ; mask out serial bits
  527.      move.l   vb_SaveDDRA(a5),d1              ; get saved value
  528.      andi.b   #~PRTMASK,d1                  ; mask out printer bits
  529.      or.b      d1,d0                   ; combine the two
  530.      move.b   d0,ciaddra(a0)              ; and store
  531.      ;
  532.      lea      timerReq(pc),a1              ; get ptr to timer request
  533.      jsr      _LVOCloseDevice(a6)              ; go close it
  534.      ;
  535.      move.l   vb_MiscBase(a5),a6              ; get MiscBase
  536.      moveq      #MR_SERIALBITS,d0              ; set unit
  537.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  538.      ;
  539.      moveq      #MR_SERIALPORT,d0              ; set unit
  540.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  541.      move.l   SysBase(pc),a6              ; restore ExecBase
  542.      ;
  543.     IFNE DANGER
  544.      subq.b   #1,IDNestCnt(a6)
  545.      bge.b      enable$
  546.      move.w   #$0C000,_intena              ; enable interrupts
  547. enable$
  548.     ELSE
  549.      jsr      _LVOEnable(a6)              ; enable interrupts
  550.     ENDC
  551.      ;
  552.      subq.l   #1,vb_Initialized(a5)           ; clear flag
  553.      moveq      #0,d0                   ; free up everything
  554.      ;
  555. 10$     move.l   (sp)+,a1                  ; restore registers
  556.      ;
  557.      move.l   a5,a6                   ; restore base
  558.      move.l   (sp)+,a5                  ; restore registers
  559.      ;
  560.      tst.l      d0                      ; freed?
  561.      bne.b      dev_Null                  ; nope, can't expunge, exit
  562.      ;
  563.      clr.l      vb_SerFlags(a6)              ; clear flags
  564.      ;
  565.      btst      #LIBB_DELEXP,LIB_FLAGS(a6)
  566.      beq.b      dev_Null
  567.      ;
  568.      ;      Device Expunge routine (also fall through from dev_Close)
  569.      ;
  570. dev_Expunge:
  571.      ori.b      #1<<LIBB_DELEXP,LIB_FLAGS(a6)       ; Set expunge flag
  572.      tst.w      LIB_OPENCNT(a6)              ; currently open?
  573.      bne.b      dev_Null                  ; yep, so just exit
  574.      ;
  575.      move.l   vb_SegList(a6),d0              ; get seglist ptr
  576.      move.l   d0,-(sp)                  ; save registers (save D0!)
  577.      ;
  578.      move.l   a6,a1                   ; get base
  579.      ; This is the REMOVE macro
  580.      move.l   (a1)+,a0
  581.      move.l   (a1),a1                  ; LN_PRED
  582.      move.l   a0,(a1)
  583.      move.l   a1,LN_PRED(a0)
  584.      ;      Library
  585.      move.l   a6,a1                   ; get base
  586.      moveq      #0,d0                   ; clear work
  587.      move.w   LIB_NEGSIZE(a6),d0              ; calculate
  588.      suba.l   d0,a1                   ;   memory address
  589.      add.w      LIB_POSSIZE(a6),d0              ;     and size
  590.      move.l   a6,-(sp)                  ; save registers
  591.      move.l   SysBase(pc),a6              ; get ExecBase
  592.      jsr      _LVOFreeMem(a6)              ; free it
  593.      ;
  594.      move.l   (sp)+,a6                  ; restore registers
  595.      move.l   (sp)+,d0                  ; restore registers
  596.      rts                          ; return (seglist in D0!)
  597.      ;
  598.      ;      Device "ExtFunc" routine
  599.      ;
  600.      cnop 0,4 ; align for 020+
  601. dev_Null:
  602.      moveq      #0,d0                   ; set return code
  603.      rts                          ; return
  604.      ;
  605.      ;
  606.      ;
  607.      ;
  608.      cnop 0,4 ; align for 020+
  609. cmdTable dc.l      cmd_Invalid-cmdTable              ; CMD_INVALID
  610.      dc.l      cmd_Reset-cmdTable              ; CMD_RESET
  611.      dc.l      cmd_Read-cmdTable              ; CMD_READ
  612.      dc.l      cmd_Write-cmdTable              ; CMD_WRITE
  613.      dc.l      cmd_Invalid-cmdTable              ; CMD_UPDATE
  614.      dc.l      cmd_Clear-cmdTable              ; CMD_CLEAR
  615.      dc.l      cmd_Invalid-cmdTable              ; CMD_STOP
  616.      dc.l      cmd_Invalid-cmdTable              ; CMD_START
  617.      dc.l      cmd_Flush-cmdTable              ; CMD_FLUSH
  618.      dc.l      sdcmd_Query-cmdTable              ; SDCMD_QUERY   (CMD_NONSTD)
  619.      dc.l      sdcmd_Break-cmdTable              ; SDCMD_BREAK
  620.      dc.l      sdcmd_SetParams-cmdTable          ; SDCMD_SETPARAMS
  621. endTable
  622.      dc.l      nscmd_DeviceQuery-cmdTable          ; NSCMD_DEVICEQUERY
  623. nsendTable
  624.      ;
  625.      ;      Device BeginIO routine
  626.      ;
  627.      cnop 0,4 ; align for 020+
  628. dev_BeginIO:
  629.     IFNE STATS
  630.      movem.l  d0-d7/a0-a6,-(sp)
  631.      lea      .stata,a0
  632.      suba.l   a1,a1
  633.      jsr      KPrintF(pc)
  634.      movem.l  (sp)+,d0-d7/a0-a6
  635.      bra.b      .statend
  636.      cnop 0,4 ; align for 020+
  637. .stata     dc.b      'Started dev_BeginIO',13,10,0
  638.      cnop 0,4 ; align for 020+
  639. .statend
  640.     ENDC
  641.      move.l   a5,-(sp)                  ; save register
  642.      move.l   a6,a5                   ; save base
  643.      move.l   SysBase(pc),a6              ; get ExecBase
  644.      ;
  645.      move.b   #NT_MESSAGE,LN_TYPE(a1)          ; set type
  646.      clr.b      IO_ERROR(a1)                  ; clear error
  647.      ;
  648.      andi.b   #~(IOSERF_QUEUED|IOSERF_ACTIVE),IO_FLAGS(a1) ; clear flags
  649.      ;
  650.      moveq      #0,d0
  651.      move.w   IO_COMMAND(a1),d0              ; get command
  652.      lsl.l      #2,d0                   ; multiply by 4
  653.      moveq      #endTable-cmdTable,d1
  654.      cmp.l      d1,d0                   ; in range?
  655.      bcc.b      25$                      ; nope, branch
  656.      ;
  657. 5$     move.l   cmdTable(pc,d0.l),d0              ; get routine offset
  658.      jsr      cmdTable(pc,d0.l)              ; go do it
  659.      tst.l      d0                      ; I/O completed?
  660.      bne.b      19$                      ; nope, go return
  661.      ;
  662. 10$     btst      #IOB_QUICK,IO_FLAGS(a1)          ; need to reply?
  663.      bne.b      20$                      ; nope, branch
  664. 15$     jsr      _LVOReplyMsg(a6)              ; send it back
  665.      ;
  666. 19$     andi.b   #~(1<<IOB_QUICK),IO_FLAGS(a1)       ; clear quick bit
  667. 20$     move.l   a5,a6                   ; restore base
  668.      move.l   (sp)+,a5                  ; restore register
  669.     IFNE STATS
  670.      movem.l  d0-d7/a0-a6,-(sp)
  671.      lea      .statb,a0
  672.      suba.l   a1,a1
  673.      jsr      KPrintF(pc)
  674.      movem.l  (sp)+,d0-d7/a0-a6
  675.      bra.b      .statenda
  676.      cnop 0,4 ; align for 020+
  677. .statb     dc.b      'Finished dev_BeginIO',13,10,0
  678.      cnop 0,4 ; align for 020+
  679. .statenda
  680.     ENDC
  681.      rts                          ; return
  682.      cnop 0,4 ; align for 020+
  683. 25$     cmp.l      #(4*NSCMD_DEVICEQUERY),d0
  684.      bne.b      30$
  685.      move.l   d1,d0
  686.      bra.b      5$
  687.      cnop 0,4 ; align for 020+
  688.      ;
  689. 30$     move.b   #IOERR_NOCMD,IO_ERROR(a1)          ; invalid command
  690.      bra.b      10$                      ; branch
  691.      ;
  692.      ;      Device AbortIO routine
  693.      ;
  694.      cnop 0,4 ; align for 020+
  695. dev_AbortIO:
  696.     IFNE STATS
  697.      movem.l  d0-d7/a0-a6,-(sp)
  698.      lea      .stata,a0
  699.      suba.l   a1,a1
  700.      jsr      KPrintF(pc)
  701.      movem.l  (sp)+,d0-d7/a0-a6
  702.      bra.b      .statend
  703.      cnop 0,4 ; align for 020+
  704. .stata     dc.b      'Started dev_AbortIO',13,10,0
  705.      cnop 0,4 ; align for 020+
  706. .statend
  707.     ENDC
  708.      move.l   a5,-(sp)                  ; save registers
  709.      move.l   a6,a5                   ; save base
  710.      move.l   SysBase(pc),a6              ; get ExecBase
  711.      ;
  712.     IFNE DANGER
  713.      move.w   #$04000,_intena
  714.      addq.b   #1,IDNestCnt(a6)              ; disable interrupts
  715.     ELSE
  716.      jsr      _LVODisable(a6)              ; disable interrupts
  717.     ENDC
  718.      ;   IORequest
  719.      move.l   IO_COMMAND(a1),d1              ; get flags
  720.      btst      #IOSERB_QUEUED+8,d1              ; queued request?
  721.      bne.b      40$                      ; yep, branch
  722.      ;
  723.      btst      #IOSERB_ACTIVE+8,d1              ; active request?
  724.      beq.b      10$                      ; nope, just exit
  725.      ;
  726.      move.l   d1,d0                   ; get command
  727.      swap      d0
  728.      subq.w   #CMD_READ,d0                  ; was it a read?
  729.      beq.b      20$                      ; yep, go process
  730.      ;
  731.      subq.w   #CMD_WRITE-CMD_READ,d0          ; was it a write?
  732.      beq.b      30$                      ; yep, go process
  733.      ;
  734.      subq.w   #SDCMD_BREAK-CMD_WRITE,d0          ; was it a break?
  735.      beq.b      30$                      ; yep, go process
  736.      ;
  737.      ;      Fall through or enter from below
  738.      ;
  739.     IFNE DANGER
  740. 10$     subq.b   #1,IDNestCnt(a6)
  741.      bge.b      enable$
  742.      move.w   #$0C000,_intena              ; enable interrupts
  743. enable$
  744.     ELSE
  745. 10$     jsr      _LVOEnable(a6)              ; enable ints and return
  746.     ENDC
  747. 15$     move.l   a5,a6                   ; restore base
  748.      move.l   (sp)+,a5                  ; restore registers
  749.     IFNE STATS
  750.      movem.l  d0-d7/a0-a6,-(sp)
  751.      lea      .statb,a0
  752.      suba.l   a1,a1
  753.      jsr      KPrintF(pc)
  754.      movem.l  (sp)+,d0-d7/a0-a6
  755.      rts
  756.      cnop 0,4 ; align for 020+
  757. .statb     dc.b      'Finished dev_AbortIO',13,10,0
  758.      cnop 0,4 ; align for 020+
  759.     ENDC
  760.      rts                          ; return
  761.      ;
  762.      ;      Abort an active read request
  763.      ;
  764. 20$     clr.l      cr_IOReq                  ; no longer active
  765.      bra.b      50$                      ; go set flags
  766.      ;
  767.      ;      Abort an active write request
  768.      ;
  769.      cnop 0,4 ; align for 020+
  770. 30$     clr.l      cw_Length                  ; no longer active
  771.      clr.l      cw_IOReq                  ; no longer active
  772.      move.l   cw_Buffer(pc),d0              ; get buffer ptr
  773.      sub.l      IO_DATA(a1),d0              ; calc number of bytes xfer'd
  774.      move.l   d0,IO_ACTUAL(a1)              ; store
  775.      ;
  776.      ;      Force a TBE interrupt to get the next write going.
  777.      ;
  778.      move.w   #INTF_SETCLR|INTF_TBE,_intreq       ; make TBE pending
  779.      bra.b      50$                      ; go set flags
  780.      ;
  781.      ;      Remove I/O from queue.
  782.      ;
  783.      cnop 0,4 ; align for 020+
  784. 40$     move.l   a1,-(sp)                  ; save ptr
  785.      ; This is the REMOVE macro
  786.      move.l   (a1)+,a0
  787.      move.l   (a1),a1                  ; LN_PRED
  788.      move.l   a0,(a1)
  789.      move.l   a1,LN_PRED(a0)
  790.      ;
  791.      move.l   (sp)+,a1                  ; restore ptr
  792.      ;
  793.      ;      Set error and return I/O
  794.      ;
  795. 50$     move.b   #IOERR_ABORTED,IO_ERROR(a1)          ; set error code
  796.      move.b   IO_FLAGS(a1),d1              ; get flags
  797.      ori.b      #1<<IOSERB_ABORT,d1              ; set abort flag
  798.      andi.b   #~(IOSERF_QUEUED|IOSERF_ACTIVE),d1  ; clear flags
  799.      move.b   d1,IO_FLAGS(a1)              ; store flags
  800.      btst      #IOB_QUICK,d1               ; need to reply?
  801.      bne.b      10$                      ; nope, branch
  802.      jsr      _LVOReplyMsg(a6)              ; send it back
  803.      bra.b      10$                      ; branch to return
  804.      ;
  805.      ;      Abort all active/queued commands and reset internal state
  806.      ;
  807.      cnop 0,4 ; align for 020+
  808. cmd_Reset:
  809.      move.l   a1,-(sp)                  ; save I/O request
  810.      bsr.b      cmd_Flush                  ; go abort queued requests
  811.      ;
  812.     IFNE DANGER
  813.      move.w   #$04000,_intena
  814.      addq.b   #1,IDNestCnt(a6)              ; disable interrupts
  815.     ELSE
  816.      jsr      _LVODisable(a6)              ; disable interrupts
  817.     ENDC
  818.      ;
  819.      ;      This must follow the DISABLE
  820.      ;
  821.      exg      a5,a6                   ; exchange base and ExecBase
  822.      ;
  823.      move.l   cr_IOReq(pc),d0              ; active read?
  824.      beq.b      10$                      ; nope, branch
  825.      move.l   d0,a1                   ; get I/O request
  826.      bsr      dev_AbortIO                  ; go abort it
  827.      ;
  828.      ;
  829.      ;
  830. 10$     move.l   cw_IOReq(pc),d0              ; active write?
  831.      beq.b      20$                      ; nope, branch
  832.      move.l   d0,a1                   ; get I/O request
  833.      bsr      dev_AbortIO                  ; go abort it
  834.      ;
  835. 20$     exg      a5,a6                   ; restore base and ExecBase
  836.      move.l   (sp)+,a1                  ; restore I/O request
  837.      moveq      #8,d0                   ; get char size
  838.      move.b   d0,IO_READLEN(a1)              ; set read length
  839.      move.b   d0,IO_WRITELEN(a1)              ; set write length
  840.      moveq      #1,d0                   ; get stop bits
  841.      move.b   d0,IO_STOPBITS(a1)              ; set stop bits (IOExtSer)
  842.      move.l   vb_DefBaud(a5),IO_BAUD(a1)          ; set to default baud
  843.      move.l   vb_DefRBufLen(a5),IO_RBUFLEN(a1)    ; set to default buflen
  844.      bsr      internalReset               ; go set/verify parameters
  845.      move.b   d0,IO_ERROR(a1)              ; set error code
  846.      ;
  847.      ;      Set RC
  848.      ;
  849.      moveq      #0,d0                   ; I/O complete
  850.     IFNE DANGER
  851.      subq.b   #1,IDNestCnt(a6)
  852.      bge.b      enable$
  853.      move.w   #$0C000,_intena              ; enable interrupts
  854. enable$  rts                          ; return
  855.     ELSE
  856.      jmp      _LVOEnable(a6)              ; enable interrupts
  857.                               ; return
  858.     ENDC
  859.      ;
  860.      ;      Abort all "queued" requests, leaving all active alone.
  861.      ;
  862.      cnop 0,4 ; align for 020+
  863. cmd_Flush:
  864.      move.l   a2,-(sp)                  ; save registers
  865.      move.l   a1,-(sp)                  ; save registers
  866.      ;
  867.      ;      Abort all queued read requests.
  868.      ;
  869.      lea      readQ(pc),a2                  ; get ptr to read queue
  870.      bsr.b      20$                      ; branch to abort
  871.      ;
  872.      ;      Abort all queued write requests.
  873.      ;
  874.      lea      writeQ(pc),a2               ; get ptr to write queue
  875.      bsr.b      20$                      ; branch to abort
  876.      ;
  877.      ;      restore, and return to caller
  878.      ;
  879.      move.l   (sp)+,a1                  ; restore registers
  880.      move.l   (sp)+,a2                  ; restore registers
  881.      ;
  882.      ;      Set RC and return
  883.      ;
  884.      moveq      #0,d0                   ; I/O complete
  885.      ;
  886.      ;      !!!NOTE!!!  In a mad attempt to save 2 bytes, this RTS is used
  887.      ;      by the subroutine below.  Why waste 'em?  B-)
  888.      ;
  889. 10$     rts                          ; return ( used below too!! )
  890.      ;
  891.      ;      Subroutine to remove and reply each I/O request.
  892.      ;
  893.      cnop 0,4 ; align for 020+
  894.     IFNE DANGER
  895. 20$     move.l   #custom+intena,a0
  896.      move.w   #$04000,(a0)
  897.      addq.b   #1,IDNestCnt(a6)              ; disable interrupts
  898.     ELSE
  899. 20$     jsr      _LVODisable(a6)              ; disable interrupts
  900.     ENDC
  901.      move.l   a2,8(a2)                  ; clear list
  902.      move.l   (a2)+,a1                  ; and get ptr to first I/O request
  903.      move.l   a2,-(a2)                  ;
  904.      move.l   a1,a2                   ; save I/O request in a2
  905.      ;
  906.     IFNE DANGER
  907.      subq.b   #1,IDNestCnt(a6)
  908.      bge.b      enable$
  909.      move.w   #$0C000,(a0)                  ; enable interrupts
  910. enable$
  911.     ELSE
  912.      jsr      _LVOEnable(a6)              ; enable interrupts
  913.     ENDC
  914.      ;
  915. 25$     move.l   (a2),d0                  ; get next I/O request
  916.      beq.b      10$                      ; end of list? yep, branch to return
  917.      ;
  918.      move.l   a2,a1                   ; move I/O request to a1
  919.      move.l   d0,a2                   ; save next I/O request in a2
  920.      andi.b   #~(1<<IOSERB_QUEUED),IO_FLAGS(a1)   ; no longer queued
  921.      moveq      #IOERR_ABORTED,d0              ; indicate aborted
  922.      move.b   d0,IO_ERROR(a1)              ; store status
  923.      ;
  924.      jsr      _LVOReplyMsg(a6)              ; send it back
  925.      bra.b      25$                      ; continue with next
  926.      ;
  927.      ;      Process a CMD_READ request.
  928.      ;
  929.      cnop 0,4 ; align for 020+
  930. cmd_Read:
  931.      ;
  932.      ;      Zero length requests just get returned.
  933.      ;
  934.      clr.l      IO_ACTUAL(a1)               ; clear bytes read
  935.      move.l   IO_LENGTH(a1),d0              ; get length and test
  936.      beq.b      20$                      ; yep, leave
  937.      ;
  938.      ;      This can be used to circumvent a bug in NComm 3.0 which
  939.      ;      references the buffer even when there was nothing read.
  940.      ;
  941.     IFNE     NCOMM
  942.      move.l   IO_DATA(A1),a0              ; get data pointer
  943.      clr.b      (a0)                      ; clear first byte in buffer
  944.     ENDC
  945.      ;
  946.      ;      The disable counter works just like exec's TDNestCnt field.  It's
  947.      ;      initialized to -1.  After incrementing, if it is 0, then we
  948.      ;      can attempt to process this request immediately.  If it's > 0,
  949.      ;      then we're already disabled and we must queue this request.
  950.      ;
  951.      addq.l   #1,disableRead              ; incr disable count
  952.      bgt.b      50$                      ; >0, already disabled
  953.      ;
  954.      ;      If we're already processing an request, this one has to wait
  955.      ;      until that one is done, so go queue it.
  956.      ;
  957.      tst.l      cr_IOReq(pc)                  ; have an active request?
  958.      bne.b      50$                      ; yep, go queue this one
  959.      ;
  960.      ;      If we don't have enough bytes to satisfy this request then go
  961.      ;      queue it.
  962.      ;
  963.      cmp.l      i_InCnt(pc),d0              ; length > current bytes?
  964.      bgt.b      50$                      ; yep, go queue it
  965.      ;
  966.      ;      Setup fields and go copy the data
  967.      ;
  968.     IFNE NCOMM
  969.      move.l   a0,cr_OutPtr                  ; get/set output ptr
  970.     ELSE
  971.      move.l   IO_DATA(a1),cr_OutPtr           ; get/set output ptr
  972.     ENDC
  973.      move.l   d0,cr_Length                  ; get/set output count
  974.      bsr      copyData                  ; go copy 'em
  975.      moveq      #0,d0                   ; I/O complete
  976.      ;
  977.      ;      We're done, so back off the disable counter.
  978.      ;
  979. 10$     subq.l   #1,disableRead              ; decr disable count
  980.      ;
  981.      ;      Return to caller
  982.      ;
  983. 20$     rts                          ; return
  984.      ;
  985.      ;      Just set flags and queue.  The read interrupt will handle it.
  986.      ;
  987.      cnop 0,4 ; align for 020+
  988. 50$     ori.b      #1<<IOSERB_QUEUED,IO_FLAGS(a1)    ; indicate queued
  989.      ;
  990.      ;      Add this request to the end.
  991.      ;
  992.     IFNE DANGER
  993.      move.w   #$04000,_intena
  994.      addq.b   #1,IDNestCnt(a6)              ; disable interrupts
  995.     ELSE
  996.      jsr      _LVODisable(a6)              ; disable interrupts
  997.     ENDC
  998.      lea      readQ(pc),a0                  ; get pointer to read queue
  999.      ; This is the ADDTAIL macro
  1000.      addq.l   #LH_TAIL,a0
  1001.      move.l   LN_PRED(a0),d0
  1002.      move.l   a1,LN_PRED(a0)
  1003.      move.l   a0,(a1)                  ;
  1004.      move.l   d0,4(a1)                  ;
  1005.      move.l   d0,a0
  1006.      move.l   a1,(a0)
  1007.      ;
  1008.      ;
  1009.      ;      Indicate that this request was not handled immediatly.
  1010.      ;
  1011.      moveq      #1,d0                   ; I/O not complete
  1012.     IFNE DANGER
  1013.      subq.b   #1,IDNestCnt(a6)
  1014.      bge.b      10$
  1015.      move.w   #$0C000,_intena              ; enable interrupts
  1016.     ELSE
  1017.      jsr      _LVOEnable(a6)              ; enable interrupts
  1018.     ENDC
  1019.      bra.b      10$                      ; branch to return
  1020.      ;
  1021.      ;      Process a CMD_WRITE request.
  1022.      ;
  1023.      cnop 0,4 ; align for 020+
  1024. cmd_Write:
  1025.      clr.l      IO_ACTUAL(a1)               ; clear bytes written
  1026.      move.l   IO_LENGTH(a1),d0              ; get length
  1027.      beq.b      inv_rt                  ; nope, fin
  1028.     IFNE EOFCODE
  1029.      btst      #SERB_EOFMODE,IO_SERFLAGS(a1)       ; EOFMODE requested?
  1030.      bne.b      eoferr                  ; yep, branch
  1031.     ENDC
  1032.     IFNE NEGCHECK
  1033.      ;
  1034.      ; Check for -1 length
  1035.      ;
  1036.      moveq      #-1,d1                  ; get value
  1037.      cmp.l      d1,d0                   ; length = -1?
  1038.      beq.b      negcheck                  ; yep, do scan
  1039.     ENDC
  1040.      ;
  1041.      ;      Entry point for Break command and fall through from cmd_Write.
  1042.      ;
  1043. sdcmd_Break:
  1044.      ;
  1045.      ;      Just set flags and queue. The TBE interrupt will handle it.
  1046.      ;
  1047.      ori.b      #1<<IOSERB_QUEUED,IO_FLAGS(a1)      ; indicate queued
  1048.      ;
  1049.      ;      Protect.
  1050.      ;
  1051.     IFNE DANGER
  1052.      move.w   #$04000,_intena
  1053.      addq.b   #1,IDNestCnt(a6)              ; disable interrupts
  1054.     ELSE
  1055.      jsr      _LVODisable(a6)              ; disable interrupts
  1056.     ENDC
  1057.      ;
  1058.      ;      Add request to end of queue.
  1059.      ;
  1060.      lea      writeQ(pc),a0               ; get queue list ptr
  1061.      ; This is the ADDTAIL macro
  1062.      addq.l   #LH_TAIL,a0
  1063.      move.l   LN_PRED(a0),d0
  1064.      move.l   a1,LN_PRED(a0)
  1065.      move.l   a0,(a1)
  1066.      move.l   d0,4(a1)
  1067.      move.l   d0,a0
  1068.      move.l   a1,(a0)
  1069.      ;
  1070.      ;      If we have an active request, don't force interrupt.
  1071.      ;
  1072.      tst.l      cw_IOReq(pc)                  ; have an active request?
  1073.      bne.b      10$                      ; yep, branch
  1074.      ;
  1075.      ;      Force a TBE interrupt to get the writes going.
  1076.      ;
  1077.      move.w   #INTF_SETCLR|INTF_TBE,_intreq       ; make TBE pending
  1078.      ;
  1079.      ;      Enable, set RC and return to caller.
  1080.      ;
  1081. 10$     moveq      #1,d0                   ; I/O not complete
  1082.     IFNE DANGER
  1083.      subq.b   #1,IDNestCnt(a6)
  1084.      bge.b      enable$
  1085.      move.w   #$0C000,_intena              ; enable interrupts
  1086. enable$  rts                          ; return
  1087.     ELSE
  1088.      jmp      _LVOEnable(a6)              ; enable interrupts
  1089.                               ; return
  1090.     ENDC
  1091.     IFNE EOFCODE
  1092.      cnop 0,4 ; align for 020+
  1093. eoferr:
  1094.     IFNE STATS
  1095.      movem.l  d0-d7/a0-a6,-(sp)
  1096.      lea      .statb,a0
  1097.      suba.l   a1,a1
  1098.      jsr      KPrintF(pc)
  1099.      movem.l  (sp)+,d0-d7/a0-a6
  1100.      rts
  1101.      cnop 0,4 ; align for 020+
  1102. .statb     dc.b      'ERROR: EOFMODE in Write',13,10,0
  1103.      cnop 0,4 ; align for 020+
  1104.     ENDC
  1105.      moveq      #SerErr_InvParam,d0              ; SerErr_InvParam instead?
  1106.      move.b   d0,IO_ERROR(a1)              ; Set error
  1107.      moveq      #0,d0                   ; I/O Complete
  1108.      rts
  1109.     ENDC
  1110.     IFNE NEGCHECK
  1111.      ;
  1112.      ;      Scan the data for null to calc the length
  1113.      ;
  1114.      cnop 0,4 ; align for 020+
  1115. negcheck:
  1116.      move.l   IO_DATA(a1),a0              ; get data ptr
  1117.      move.l   a0,d1                   ; save data ptr
  1118. 10$     tst.b      (a0)+                   ; does it equal 0? (first byte)
  1119.      beq.b      20$                      ; yep, finish
  1120.      tst.b      (a0)+                   ; does it equal 0? (second byte)
  1121.      beq.b      20$                      ; yep, finish
  1122.      tst.b      (a0)+                   ; does it equal 0? (third byte)
  1123.      beq.b      20$                      ; yep, finish
  1124.      tst.b      (a0)+                   ; does it equal 0? (fourth byte)
  1125.      bne.b      10$                      ; nope, loop
  1126. 20$     move.l   a0,d0
  1127.      sub.l      d1,d0                   ; calc # of bytes
  1128.      move.l   d0,IO_LENGTH(a1)              ; save length
  1129.      bra.b      sdcmd_Break
  1130.     ENDC
  1131.      ;
  1132.      ;      Resets serial read buffer
  1133.      ;
  1134.      ;      Since this routine is called internally, it must NOT reference
  1135.      ;      the I/O request.
  1136.      ;
  1137.      cnop 0,4 ; align for 020+
  1138. cmd_Clear:
  1139.     IFNE DANGER
  1140.      move.w   #$04000,_intena
  1141.      addq.b   #1,IDNestCnt(a6)              ; disabel interrupts
  1142.     ELSE
  1143.      jsr      _LVODisable(a6)              ; disable interrupts
  1144.     ENDC
  1145.      ;
  1146.      ;      Load registers
  1147.      ;
  1148.      move.l   vb_CurRBuf(a5),d0              ; get internal buffer ptr
  1149.      move.l   vb_CurRBufLen(a5),d1              ; and internal buffer len
  1150.      lea      i_BufPtr(pc),a0              ; get ptr internal control
  1151.      ;
  1152.      ;      Initialize global buffer variables
  1153.      ;
  1154.      move.l   d0,(a0)+                  ; store buffer ptr
  1155.      move.l   d0,(a0)+                  ; set current input ptr
  1156.      move.l   d0,(a0)+                  ; set current output ptr
  1157.      add.l      d1,d0                   ; add buffer length
  1158.      move.l   d0,(a0)+                  ; store ptr to end of buffer
  1159.      clr.l      (a0)+                   ; clear byte cnt
  1160.      move.l   vb_CurBaud(a5),d0              ; get internal baud
  1161.      lsr.l      #4,d0                   ; divide by 16
  1162.      sub.l      d0,d1                   ; subtract from length
  1163.      move.l   d1,(a0)                  ; set threshold
  1164.      ;
  1165.      ;      Enable, set RC and return.
  1166.      ;
  1167.      moveq      #0,d0                   ; I/O complete
  1168.     IFNE DANGER
  1169.      subq.b   #1,IDNestCnt(a6)
  1170.      bge.b      enable$
  1171.      move.w   #$0C000,_intena              ; enable interrupts
  1172. enable$  rts                          ; return
  1173.     ELSE
  1174.      jmp      _LVOEnable(a6)              ; enable interrupts
  1175.                               ; return
  1176.     ENDC
  1177.      ;
  1178.      ;
  1179.      ;
  1180.      cnop 0,4 ; align for 020+
  1181. cmd_Invalid
  1182.      move.b   #IOERR_NOCMD,IO_ERROR(a1)          ; set bad status
  1183.      moveq      #0,d0                   ; I/O complete
  1184. inv_rt     rts                          ; return
  1185.      ;
  1186.      ;      Returns number of bytes currently in internal buffer and
  1187.      ;      current serial port status.
  1188.      ;
  1189.      ;      NOTE:  Not completely compatible with standard serial.device
  1190.      ;      since it doesn't return the upper byte of IO_STATUS.
  1191.      ;
  1192.      cnop 0,4 ; align for 020+
  1193. sdcmd_Query:
  1194.     IFNE DANGER
  1195.      move.l   #custom+intena,a0
  1196.      move.w   #$04000,(a0)
  1197.      addq.b   #1,IDNestCnt(a6)              ; disable interrupts
  1198.     ELSE
  1199.      jsr      _LVODisable(a6)              ; disable interrupts
  1200.     ENDC
  1201.      moveq      #0,d0                   ; clear d0
  1202.      move.b   _ciabpra,d0                  ; get PR register
  1203.      andi.b   #~PRTMASK,d0                  ; zap printer bits
  1204.      ;
  1205.      ;      To use this Set SETDSR to one.  This was done
  1206.      ;      for a user whose DSR pin did not function.
  1207.      ;
  1208.     IFNE SETDSR
  1209.      andi.b     #~(1<<CIAB_COMDSR),d0              ; set DSR
  1210.     ENDC
  1211.      ;
  1212.      ;
  1213.      ;
  1214.      move.w   d0,IO_STATUS(a1)              ; store status
  1215.      move.l   i_InCnt(pc),IO_ACTUAL(a1)          ; byte left in buffer
  1216.      ;
  1217.      ;      Enable, set RC and return.
  1218.      ;
  1219.      moveq      #0,d0                   ; I/O complete
  1220.     IFNE DANGER
  1221.      subq.b   #1,IDNestCnt(a6)
  1222.      bge.b      enable$
  1223.      move.w   #$0C000,(a0)                  ; enable interrupts
  1224. enable$  rts                          ; return
  1225.     ELSE
  1226.      jmp      _LVOEnable(a6)              ; enable interrupts
  1227.                               ; return
  1228.     ENDC
  1229.      ;
  1230.      ;
  1231.      ;
  1232.      cnop 0,4 ; align for 020+
  1233. sdcmd_SetParams:
  1234.      ;
  1235.      ;      Validate the read, write, and stop bit lengths.
  1236.      ;
  1237.      moveq      #8,d0                   ; get char length
  1238.      cmp.b      IO_READLEN(a1),d0              ; 8 bit chars for read?
  1239.      bne.b      40$                      ; nope, branch
  1240.      cmp.b      IO_WRITELEN(a1),d0              ; 8 bit chars for write?
  1241.      bne.b      40$                      ; nope, branch
  1242.      moveq      #1,d0                   ; get stop bits
  1243.      cmp.b      IO_STOPBITS(a1),d0              ; 1 stop bit?
  1244.      bne.b      40$                      ; nope, branch
  1245.      ;
  1246.      ;      Get and validate the baud rate.
  1247.      ;
  1248.      move.l   IO_BAUD(a1),d1              ; get baud from I/O req
  1249.      bne.b      20$                      ; specified?
  1250.      move.l   vb_CurBaud(a5),d1              ; get current baud from base
  1251.      bne.b      20$                      ; specified?
  1252.      move.l   vb_DefBaud(a5),d1              ; get default baud from base
  1253. 20$     moveq      #110,d0
  1254.      cmp.l      d0,d1                   ; too low?
  1255.      blt.b      40$                      ; error
  1256.      cmp.l      #292000,d1                  ; too high?
  1257.      bgt.b      40$                      ; error
  1258.      ;
  1259.      ;      Get and validate the buffer length.
  1260.      ;
  1261.      move.l   IO_RBUFLEN(a1),d0              ; get buffer length
  1262.      bne.b      30$                      ; specified?
  1263.      move.l   vb_CurRBufLen(a5),d0              ; get current from base
  1264.      bne.b      30$                      ; specified?
  1265.      move.l   vb_DefRBufLen(a5),d0              ; get default from base
  1266.      ;
  1267. 30$     bsr.b      internalReset               ; go init baud and buffer
  1268. 35$     move.b   d0,IO_ERROR(a1)              ; set error code
  1269.      bne.b      39$
  1270.      ;
  1271.      ;      If the 7wire bit is not on, we will only use 3-wire protocol
  1272.      ;
  1273.      moveq      #0,d0                   ; clear flag
  1274.      btst      #SERB_7WIRE,IO_SERFLAGS(a1)          ; use 7wire handshaking?
  1275.      beq.b      36$                      ; nope, branch
  1276.      moveq      #1,d0                   ; set flag
  1277. 36$     move.l   d0,Handshake                  ; store flag
  1278.      ;
  1279.      ;      Set RC and return.
  1280.      ;
  1281. 39$     moveq      #0,d0                   ; I/O complete
  1282.      rts                          ; return
  1283.      ;
  1284.      ;      Invalid parm detected.
  1285.      ;
  1286. 40$     moveq      #SerErr_InvParam,d0              ; set error
  1287.      bra.b      35$                      ; go return
  1288.      ;
  1289.      ;  The NewStyleDevices Query command.
  1290.      ;
  1291.      cnop 0,4 ; align for 020+
  1292. nscmd_DeviceQuery:
  1293.      move.l   IO_DATA(a1),d0
  1294.      beq.b      10$
  1295.      move.l   d0,a0
  1296.      moveq      #NSDEVICEQUERYRESULT_SIZE,d0
  1297.      move.l   d0,SIZEAVAILABLE(a0)
  1298.      move.l   d0,IO_ACTUAL(a1)
  1299.      move.w   #NSDEVTYPE_SERIAL,DEVICETYPE(a0)
  1300.      move.w   #0,DEVICESUBTYPE(a0)
  1301.      move.l   a1,-(sp)
  1302.      lea      cmdlist(pc),a1
  1303.      move.l   a1,SUPPORTEDCOMMANDS(a0)
  1304.      move.l   (sp)+,a1
  1305. 10$     moveq      #0,d0
  1306.      rts
  1307.      ;
  1308.      ;      Reset the buffer and baud rate
  1309.      ;
  1310.      ;      Registers:  D0 = Buffer length
  1311.      ;              D1 = Baud rate
  1312.      ;
  1313.      cnop 0,4 ; align for 020+
  1314. internalReset:
  1315.      ;
  1316.      ;      Disable interrupts.
  1317.      ;
  1318.     IFNE DANGER
  1319.      move.w   #$04000,_intena
  1320.      addq.b   #1,IDNestCnt(a6)              ; disable interrupts
  1321.     ELSE
  1322.      jsr      _LVODisable(a6)              ; disable interrupts
  1323.     ENDC
  1324.      ;
  1325.      ;      Save buffer length and go set serper.
  1326.      ;
  1327.      move.l   d0,-(sp)                  ; save D0
  1328.      move.l   d1,d0                   ; get baud rate
  1329.      ;
  1330.      ;      Set serial period register
  1331.      ;
  1332.      cmp.l      vb_CurBaud(a5),d0              ; current baud = new baud?
  1333.      beq.b      40$                      ; yep, just exit
  1334.      move.l   d0,vb_CurBaud(a5)              ; save new baud
  1335.      move.l   d0,d1                   ; save again
  1336.      lsl.l      #3,d0                   ; baud *= 8
  1337.      sub.l      d1,d0                   ; baud -= saved baud
  1338.      move.l   #25000000,d1                  ; get NTSC base
  1339.      cmpi.b   #50,PowerSupplyFrequency(a6)          ; PAL machine?
  1340.      bne.b      5$                      ; nope, branch
  1341.      move.l   #24772416,d1                  ; get PAL base
  1342. 5$     cmp.l      #$FFFF,d0                  ; Divide
  1343.      ble.b      20$                      ;
  1344.      lsr.l      #5,d0                   ;
  1345.      divu.w   d0,d1                   ;
  1346.      andi.l   #$FFFF,d1                  ;
  1347.      lsr.l      #5,d1                   ;
  1348.      bra.b      30$                      ;
  1349.      cnop 0,4 ; align for 020+
  1350. 20$     divu.w   d0,d1                   ;
  1351. 30$     move.w   d1,_serper                  ; set period value
  1352. 40$     move.l   (sp)+,d0                  ; restore D0
  1353.      ;
  1354.      ;      Determine if the buffer length is adequate for the selected CPS.
  1355.      ;      If not, use 64K for the length.
  1356.      ;
  1357.      move.l   vb_CurBaud(a5),d1              ; get current baud
  1358.      lsr.l      #2,d1                   ; divide by 4
  1359.      cmp.l      d1,d0                   ; buflen > CPS
  1360.      bhi.b      10$                      ; yep, branch
  1361.      moveq      #1,d0
  1362.      swap      d0                      ; else use 64k
  1363.      ;
  1364.      ;      Allocate new internal buffer
  1365.      ;
  1366. 10$     cmp.l      vb_CurRBufLen(a5),d0              ; len same as previous?
  1367.      beq.b      11$                      ; yep, so no need to alloc
  1368.      move.l   d0,d1                   ; save length
  1369.      move.l   a1,-(sp)                  ; save registers
  1370.      move.l   d1,-(sp)                  ; save registers
  1371.      moveq      #MEMF_PUBLIC,d1              ; public memory
  1372.      jsr      _LVOAllocMem(a6)              ; go allocate it
  1373.      move.l   (sp)+,d1                  ; restore registers
  1374.      move.l   (sp)+,a1                  ; restore registers
  1375.      tst.l      d0                      ; did we get it?
  1376.      beq.b      21$                      ; if zero, error
  1377.      move.l   d0,-(sp)                  ; save d0
  1378.      bsr.b      freeBuf                  ; go free previous buffer
  1379.      move.l   (sp)+,vb_CurRBuf(a5)              ; store new ptr
  1380.      move.l   d1,vb_CurRBufLen(a5)              ; and length
  1381.      bsr      cmd_Clear                  ; go setup buffer
  1382. 11$     moveq      #0,d0                   ; success
  1383.      bra.b      22$                      ; return
  1384.      cnop 0,4 ; align for 020+
  1385. 21$     moveq      #SerErr_BufErr,d0              ; set error status
  1386. 22$
  1387.      ;
  1388.      ;      Enable and return to caller.
  1389.      ;
  1390.     IFNE DANGER
  1391.      subq.b   #1,IDNestCnt(a6)
  1392.      bge.b      enable$
  1393.      move.w   #$0C000,_intena              ; enable interrupts
  1394. enable$  rts                          ; return (D0 has status)
  1395.     ELSE
  1396.      jmp      _LVOEnable(a6)              ; enable interrupts / return (D0 has status)
  1397.     ENDC
  1398.      ;
  1399.      ;      Free internal buffer
  1400.      ;
  1401.      cnop 0,4 ; align for 020+
  1402. freeBuf:
  1403.      move.l   vb_CurRBuf(a5),d0              ; is one there?
  1404.      beq.b      10$                      ; no so branch
  1405.      move.l   a1,-(sp)                  ; save registers
  1406.      move.l   d1,-(sp)                  ; save registers
  1407.      move.l   d0,a1                   ; get ptr
  1408.      move.l   vb_CurRBufLen(a5),d0              ; get length
  1409.      clr.l      vb_CurRBuf(a5)              ; clear
  1410.      clr.l      vb_CurRBufLen(a5)              ; clear
  1411.      jsr      _LVOFreeMem(a6)              ; free it
  1412.      move.l   (sp)+,d1                  ; restore registers
  1413.      move.l   (sp)+,a1                  ; restore registers
  1414. 10$     rts                          ; return
  1415.      ;
  1416.      ;      Checks CTS status and if clear generates a TBE interrupt or
  1417.      ;      requeues the timer request.
  1418.      ;
  1419.      ;      Entered from Exec using the MsgPort callback.
  1420.      ;
  1421.      ;      Input:   a6 = ExecBase
  1422.      ;      Output:  none
  1423.      ;
  1424.      ;      No need to preserve d0/d1/a0/a1
  1425.      ;
  1426.      cnop 0,4 ; align for 020+
  1427. timerRtn:
  1428.      lea      timerReq(pc),a1              ; get ptr to timer request
  1429.      ; This is the REMOVE macro
  1430.      move.l   (a1)+,a0
  1431.      move.l   (a1),a1                  ; LN_PRED
  1432.      move.l   a0,(a1)
  1433.      move.l   a1,LN_PRED(a0)
  1434.      ;
  1435.      ;      If we were breaking, reset adkcon.
  1436.      ;
  1437.      move.l   #custom+adkconr,a0              ; get ptr to custom regs
  1438.      btst      #ADKB_UARTBRK&7,(a0)              ; were we breaking?
  1439.      beq.b      10$                      ; nope, skip reset
  1440.      ;
  1441.      move.w   #ADKF_UARTBRK,adkcon-adkconr(a0)    ; stop breaking
  1442.      ;
  1443.      ;
  1444.      ;
  1445. 10$     tst.l      Handshake(pc)               ; are we handshaking?
  1446.      beq.b      20$                      ; nope, generate interrupt
  1447.      btst      #CIAB_COMCTS,_ciabpra           ; clear to send?
  1448.      beq.b      20$                      ; yep, go start writing
  1449.      ;
  1450.      lea      timerReq(pc),a1              ; get ptr to timer request
  1451.      move.l   #1000,IOTV_TIME+TV_MICRO(a1)          ; wait for .001 seconds
  1452.      jmp      _LVOSendIO(a6)              ; go queue it / return
  1453.      ;
  1454.      ;      CTS is clear so generate TBE interrupt to restart writing
  1455.      ;
  1456.      cnop 0,4 ; align for 020+
  1457. 20$     move.w   #INTF_SETCLR|INTF_TBE,intreq-adkconr(a0)  ; set TBE interrupt
  1458.      rts                          ; return
  1459.      ;
  1460.      ;      Non serial interrupt
  1461.      ;      Handles:
  1462.      ;        INTB_DSKBLK
  1463.      ;        INTB_SOFTINT
  1464.      ;
  1465.      ;  a0 - custom chips base
  1466.      ;  a1 - is_Data
  1467.      ;
  1468.      cnop 0,4 ; align for 020+
  1469. level1n:
  1470.      move.l   a6,-(sp)                  ; save registers (16)
  1471.      move.l   a5,-(sp)
  1472.      move.l   a1,-(sp)
  1473.      move.l   d1,-(sp)
  1474.      move.l   d0,d1                   ; get enabled interrupts
  1475.      swap      d1
  1476.      move.l   SysBase(pc),a6              ; get ExecBase
  1477.      and.l      d0,d1                   ; and in requested interrupts
  1478.      ;
  1479.      btst      #INTB_DSKBLK,d1              ; Disk block done?
  1480.      beq.b      10$                      ; nope, branch
  1481.      ;
  1482.      move.l   IVDSKBLK(a6),a1              ; get data and code ptrs
  1483.      move.l   IVDSKBLK+4(a6),a5              ; get data and code ptrs
  1484.      pea      20$(pc)                  ; push return address
  1485.      jmp      (a5)                      ; jump to routine
  1486.      ;
  1487. 10$     move.l   IVSOFTINT(a6),a1              ; get data and code ptrs
  1488.      move.l   IVSOFTINT+4(a6),a5              ; get data and code ptrs
  1489.      jsr      (a5)                      ; jump to routine
  1490.      ;
  1491. 20$
  1492.      move.l   (sp)+,d1                  ; restore registers
  1493.      move.l   (sp)+,a1                  ; restore registers
  1494.      move.l   (sp)+,a5                  ; restore registers
  1495.      move.l   (sp)+,a6                  ; restore registers
  1496.      move.l   (sp)+,d0                  ; restore registers
  1497.      move.l   (sp)+,a0                  ; restore registers
  1498.      rte                          ; return
  1499.      ;
  1500.      ;    Level 1 interrupt handler
  1501.      ;    Handles:
  1502.      ;        INTB_TBE
  1503.      ;
  1504.      ;  a1 - is_Data
  1505.      ;
  1506.      cnop 0,4 ; align for 020+
  1507. level1:
  1508.      move.l   a0,-(sp)                  ; save A0 (faster than MOVEM, 4)
  1509.      move.l   d0,-(sp)                  ; save D0 (faster than MOVEM, 4)
  1510.      move.l   #custom,a0                  ; get ptr to custom regs
  1511.      move.l   intenar(a0),d0              ; get intenar & intreqr
  1512.      btst      #INTB_INTEN+16,d0              ; interrupts enabled?
  1513.      beq.b      30$                      ; nope, ignore
  1514.      btst      #INTB_TBE,d0                  ; xmit buffer empty?
  1515.      beq.b      level1n                  ; nope, invoke old handler
  1516.      ;
  1517.      ;      Handle "Transmit Buffer Empty" interrupt (write)
  1518.      ;
  1519.      move.w   #INTF_TBE,intreq(a0)              ; clear interrupt
  1520.      ;
  1521.      ;      If we're not handshaking, bypass it.
  1522.      ;
  1523. 10$     tst.l      Handshake(pc)               ; are we handshaking?
  1524.      beq.b      20$                      ; nope, skip CTS test
  1525.      btst      #CIAB_COMCTS,_ciabpra           ; clear to send?
  1526.      bne.b      40$                      ; nope, branch
  1527.      ;
  1528.      ;      If cw_Length goes negative here, we are either done with a
  1529.      ;      request or we were called as a result of a fake interrupt
  1530.      ;      to force us to get the next request going.
  1531.      ;
  1532. 20$     subq.l   #1,cw_Length                  ; decr write length
  1533.      blt.b      60$                      ; < zero, done, branch
  1534.      ;
  1535.      ;      Currently processing a request.
  1536.      ;
  1537.      move.l   cw_Buffer(pc),a0              ; get buffer ptr
  1538.      move.w   #256,d0                  ; set stop bit
  1539.      move.b   (a0)+,d0                  ; get next byte
  1540.      move.l   a0,cw_Buffer                  ; store buffer ptr
  1541.      move.w   d0,_serdat                  ; store in serdat reg
  1542.      ;
  1543. 30$     move.l   (sp)+,d0                  ; restore registers
  1544.      move.l   (sp)+,a0                  ; restore registers
  1545.      rte                          ; return
  1546.      ;
  1547.      ;      Queue a timer request to recheck CTS status
  1548.      ;
  1549.      cnop 0,4 ; align for 020+
  1550. 40$     move.l   a6,-(sp)                  ; save registers
  1551.      move.l   d1,-(sp)                  ; save registers
  1552.      move.l   a1,-(sp)                  ; save registers
  1553.      lea      timerReq(pc),a1              ; get ptr to timer request
  1554.      move.l   #1000,IOTV_TIME+TV_MICRO(a1)          ; wait for .001 seconds
  1555.      move.l   SysBase(pc),a6              ; get ExecBase
  1556.      jsr      _LVOSendIO(a6)              ; queue the request
  1557.      move.l   (sp)+,a1                  ; restore registers
  1558.      move.l   (sp)+,d1                  ; restore registers
  1559.      move.l   (sp)+,a6                  ; restore registers
  1560.      bra.b      30$                      ; go return
  1561.      ;
  1562.      ;      There aren't anymore requests, so clear and exit
  1563.      ;
  1564.      cnop 0,4 ; align for 020+
  1565. 50$     clr.l      cw_Length-Start(a6)              ; clear length
  1566.      clr.l      cw_IOReq-Start(a6)              ; clear
  1567.      move.l   (sp)+,d1                  ; restore registers
  1568.      move.l   (sp)+,a1                  ; restore registers
  1569.      move.l   (sp)+,a6                  ; restore registers
  1570.      bra.b      30$                      ; go return
  1571.      ;
  1572.      ;      Write request completed
  1573.      ;
  1574.      cnop 0,4 ; align for 020+
  1575. 60$     move.l   a6,-(sp)                  ; save registers
  1576.      move.l   a1,-(sp)                  ; save registers
  1577.      move.l   d1,-(sp)                  ; save registers
  1578.      ;
  1579.      move.l   cw_IOReq(pc),d0              ; active I/O request?
  1580.      beq.b      70$                      ; nope, branch
  1581.      ;
  1582.      ;      Reply it and setup for next
  1583.      ;
  1584.      move.l   d0,a1                   ; get I/O request
  1585.      andi.b   #~(1<<IOSERB_ACTIVE),IO_FLAGS(a1)   ; no longer active
  1586.      clr.b      IO_ERROR(a1)                  ; no error
  1587.      move.l   SysBase(pc),a6              ; get ExecBase
  1588.      jsr      _LVOReplyMsg(a6)              ; return I/O request
  1589.      ;
  1590. 70$     lea      Start(pc),a6                  ; get section base
  1591.      ;
  1592.      lea      writeQ(pc),a1               ; get ptr to write queue
  1593.      move.l   (a1),a0                  ; get head of list
  1594.      move.l   (a0),d0                  ; get successor
  1595.      beq.b      50$                      ; end of list? yep, branch
  1596.      ;
  1597.      ;      Remove the node from the list
  1598.      ;
  1599.      move.l   d0,(a1)                  ; make new head
  1600.      exg.l      d0,a0                   ; swap nodes
  1601.      move.l   a1,LN_PRED(a0)              ; store predecessor
  1602.      ;
  1603.      move.l   d0,a1                   ; get I/O request
  1604.      ;
  1605.      ;      If it's a BREAK, then branch to process as such.
  1606.      ;
  1607.      cmpi.w   #SDCMD_BREAK,IO_COMMAND(a1)          ; BREAK command?
  1608.      beq.b      100$                      ; yep, branch
  1609.      ;
  1610.      ;      Check for absolute length
  1611.      ;
  1612.      move.l   IO_DATA(a1),a0              ; get data ptr
  1613.      move.l   IO_LENGTH(a1),d0              ; get length
  1614.      move.l   d0,IO_ACTUAL(a1)              ; go ahead and set it
  1615.      move.b   IO_FLAGS(a1),d1
  1616.      move.l   d0,cw_Length-Start(a6)          ; store length
  1617.      andi.b   #~(1<<IOSERB_QUEUED),d1          ; no longer queued
  1618.      move.l   a0,cw_Buffer-Start(a6)          ; store buffer ptr
  1619.      ori.b      #1<<IOSERB_ACTIVE,d1              ; make it active
  1620.      move.l   a1,cw_IOReq-Start(a6)           ; store I/O request ptr
  1621.      move.b   d1,IO_FLAGS(a1)
  1622.      ;
  1623.      move.l   (sp)+,d1                  ; restore registers
  1624.      move.l   (sp)+,a1                  ; restore registers
  1625.      move.l   (sp)+,a6                  ; restore registers
  1626.      bra      10$                      ; go start request
  1627.      ;
  1628.      ;      Start the BREAK.
  1629.      ;
  1630.      cnop 0,4 ; align for 020+
  1631. 100$     move.b   IO_FLAGS(a1),d1
  1632.      clr.l      cw_Length-Start(a6)              ; clear length
  1633.      andi.b   #~(1<<IOSERB_QUEUED),d1          ; no longer queued
  1634.      move.l   a1,cw_IOReq-Start(a6)           ; store I/O request ptr
  1635.      ori.b      #1<<IOSERB_ACTIVE,d1              ; make it active
  1636.      move.w   #ADKF_SETCLR|ADKF_UARTBRK,_adkcon   ; start break
  1637.      move.b   d1,IO_FLAGS(a1)
  1638.      move.l   IO_BRKTIME(a1),d0              ; get break time
  1639.      lea      timerReq(pc),a1              ; get ptr to timer request
  1640.      move.l   d0,IOTV_TIME+TV_MICRO(a1)          ; set the timeout
  1641.      move.l   SysBase(pc),a6              ; get ExecBase
  1642.      jsr      _LVOSendIO(a6)              ; queue the request
  1643.      move.l   (sp)+,d1                  ; restore registers
  1644.      move.l   (sp)+,a1                  ; restore registers
  1645.      move.l   (sp)+,a6                  ; restore registers
  1646.      bra      30$                      ; go exit
  1647.      ;
  1648.      ;    Non serial interrupt
  1649.      ;    Handles:
  1650.      ;        INTB_DSKSYNC
  1651.      ;
  1652.      ;  a0 - custom chips base
  1653.      ;
  1654.      cnop 0,4 ; align for 020+
  1655. level5n:
  1656.      move.l   a6,-(sp)                  ; save registers
  1657.      move.l   a5,-(sp)                  ; save registers
  1658.      move.l   a1,-(sp)                  ; save registers
  1659.      move.l   d1,-(sp)                  ; save registers
  1660.      move.l   d0,d1
  1661.      move.l   SysBase(pc),a6              ; get ExecBase
  1662.      swap      d1
  1663.      move.l   IVDSKSYNC(A6),a1              ; get data and code ptrs
  1664.      and.l      d0,d1
  1665.      move.l   #custom,a0                  ; get ptr to custom regs
  1666.      move.l   IVDSKSYNC+4(A6),a5              ; get data and code ptrs
  1667.      jsr      (a5)                      ; branch to routine
  1668.      move.l   (sp)+,d1                  ; restore registers
  1669.      move.l   (sp)+,a1                  ; restore registers
  1670.      move.l   (sp)+,a5                  ; restore registers
  1671.      move.l   (sp)+,a6                  ; restore registers
  1672.      move.l   (sp)+,a0                  ; restore registers
  1673.      move.l   (sp)+,d0                  ; restore registers
  1674.      rte                          ; return
  1675.      ;
  1676.      ;    Default Level 5 handler
  1677.      ;    Handles:
  1678.      ;        INTB_RBF
  1679.      ;
  1680.      ;  a1 - custom chips base
  1681.      ;
  1682.      cnop 0,4 ; align for 020+
  1683. level5:
  1684.      move.l   d0,-(sp)                  ; save registers            (4)
  1685.      move.l   a0,-(sp)                  ; save registers            (4)
  1686.      move.l   #custom+serdatr,a0              ; get ptr to custom regs        (6)
  1687.      ;
  1688.      move.l   intenar-serdatr(a0),d0          ; get intenar & intreqr        (6)
  1689.      btst      #INTB_INTEN+16,d0              ; interrupts enabled?        (4)
  1690.      beq.b      41$                      ; nope, ignore            (6 or 4)
  1691.      btst      #INTB_RBF,d0                  ; receive buffer full?        (4)
  1692.      beq.b      level5n                  ; nope, invoke old handler    (6 or 4)
  1693.      ;
  1694. 10$     move.w   (a0),d0                  ; Overrun?            (5)
  1695.      bmi.b      90$                      ; yes, branch            (6 or 4)
  1696. 20$     move.w   #INTF_RBF,intreq-serdatr(a0)          ; clear RBF interrupt        (6)
  1697.      move.l   i_BufIn(pc),a0              ; get current ptr         (6)
  1698.      move.b   d0,(a0)+                  ; store received byte        (3)
  1699.      addq.l   #1,i_InCnt                  ; incr bytes in buffer        (5)
  1700.      ;
  1701.      cmpa.l   i_BufEnd(pc),a0              ; hit end of buffer?        (8)
  1702.      beq.b      91$                      ; yep, branch            (6 or 4)
  1703. 30$     move.l   a0,i_BufIn                  ; store input ptr         (4)
  1704.      ;
  1705.      subq.l   #1,i_Thresh                  ; close to full buffer?        (5)
  1706.      beq.b      92$                      ; yep, branch            (6 or 4)
  1707.      ;
  1708. 40$
  1709.     IFEQ NEWCODE
  1710.      move.l   #custom+serdatr,a0              ; get ptr to custom regs        (6)
  1711.      btst      #INTB_RBF&7,intreqr-serdatr(a0)     ; receive buffer full?        (10)
  1712.      bne.b      10$                      ; yep, go get another byte    (6 or 4)
  1713.     ENDC
  1714.      ;
  1715. 41$     move.l   (sp)+,a0                  ; restore registers        (5)
  1716.      move.l   (sp)+,d0                  ; restore registers        (5)
  1717.      rte                          ; return                (18?)
  1718.      ;
  1719.      ;      We've missed some data, so set overrun flag.
  1720.      ;
  1721.      cnop 0,4 ; align for 020+
  1722. 90$     addq.l   #1,Overrun                  ; set overrun flag
  1723.      bra.b      20$
  1724.      ;
  1725.      ;      Hit physical end of buffer, so wrap to the start of the buffer.
  1726.      ;
  1727.      cnop 0,4 ; align for 020+
  1728. 91$     move.l   i_BufPtr(pc),a0              ; get buffer ptr
  1729.      bra.b      30$
  1730.      ;
  1731.      ;      Hit buffer threshold, so tell other end not to send any more
  1732.      ;      data.
  1733.      ;
  1734.      cnop 0,4 ; align for 020+
  1735. 92$     tst.l      Handshake(pc)               ; are we handshaking?
  1736.      beq.b      40$                      ; nope, skip RTS
  1737.      ori.b      #1<<CIAB_COMRTS,_ciabpra          ; block further input
  1738.      bra.b      40$
  1739.      ;
  1740.      ;
  1741.      ;  a1 - IS_DATA
  1742.      ;  a5 - jump vector register
  1743.      ;
  1744.      cnop 0,4 ; align for 020+
  1745. level2:
  1746.      ;
  1747.      ;      If there's nothing in the buffer, there's no point in going
  1748.      ;      any further.
  1749.      ;
  1750.      tst.l      i_InCnt(pc)                  ; anything in the buffer?
  1751.      beq.b      9$                      ; nope, branch
  1752.      ;
  1753.      ;      If we've been "disabled" then get out.
  1754.      ;
  1755. 20$     tst.l      disableRead(pc)              ; internally disabled?
  1756.      bge.b      10$                      ; yep, get out of here
  1757.      lea      Start(pc),a5                  ; get base
  1758.      ;
  1759.      ;      If we have an active request, branch down and try to fulfill it.
  1760.      ;
  1761.      move.l   cr_IOReq(pc),d0              ; get and test active I/O
  1762.      bne.b      30$                      ; nzero, active, branch
  1763.      ;
  1764.      ;      Get first node in list and test if empty.
  1765.      ;
  1766.      move.l   (a1),a0                  ; get head of list
  1767.      move.l   (a0),d0                  ; get successor
  1768.      beq.b      9$                      ; end of list? yep, branch
  1769.      ;
  1770.      ;      Remove the node from the list
  1771.      ;
  1772.      move.l   d0,(a1)                  ; make new head
  1773.      exg.l      d0,a0                   ; swap nodes
  1774.      move.l   a1,LN_PRED(a0)              ; store predecessor
  1775.      ;
  1776.      ;      Setup fields for processing a read request
  1777.      ; IORequest
  1778.      move.l   d0,a1                   ; get I/O request
  1779.      move.b   IO_FLAGS(a1),d1
  1780.      andi.b   #~(1<<IOSERB_QUEUED),d1          ; no longer queued
  1781.      move.l   a1,cr_IOReq-Start(a5)           ; store I/O request
  1782.      ori.b      #1<<IOSERB_ACTIVE,d1              ; make it active
  1783.      move.l   IO_DATA(a1),cr_OutPtr-Start(a5)     ; get/set output ptr
  1784.      move.b   d1,IO_FLAGS(a1)
  1785.      move.l   IO_LENGTH(a1),cr_Length-Start(a5)   ; get/set output count
  1786.      ;
  1787.      ;      Process an active I/O request
  1788.      ;
  1789. 30$     move.l   SysBase(pc),a6              ; get ExecBase
  1790.      move.l   d0,a1                   ; get I/O request
  1791.      bsr.b      copyData                  ; go copy 'em
  1792.      tst.l      d0                      ; done with request?
  1793.      beq.b      9$                      ; nope, branch
  1794.      ;
  1795.      ;      the request has been satisfied, so return it.
  1796.      ;
  1797.      clr.l      cr_IOReq-Start(a5)              ; clear request
  1798.      andi.b   #~(1<<IOSERB_ACTIVE),IO_FLAGS(a1)   ; no longer active
  1799.      jsr      _LVOReplyMsg(a6)              ; return I/O
  1800. 10$     moveq      #0,d0                   ; set Z flag
  1801. 9$     rts                          ; return (Z flag set)
  1802.      ;
  1803.      ;      Registers:
  1804.      ;      Entry:   A1        Ptr to I/O Request
  1805.      ;           A6        ExecBase
  1806.      ;      Exit:    D0        ZERO - request not done, do not reply it
  1807.      ;                NZERO - request done, reply it
  1808.      ;
  1809.      cnop 0,4 ; align for 020+
  1810. copyData:
  1811.      ;
  1812.      ;      Process an active I/O request (or fall through from above)
  1813.      ;
  1814.      movem.l  d2-d5/a1-a5,-(sp)              ; save registers
  1815.      lea      Start(pc),a5                  ; get base
  1816.      move.l   a1,a4                   ; get I/O request
  1817.      ;
  1818.      move.l   i_BufOut(pc),a2              ; get current bufout ptr
  1819.      move.l   cr_OutPtr(pc),a3              ; get current output ptr
  1820.      move.l   cr_Length(pc),d2              ; get current bytes needed
  1821.      move.l   i_InCnt(pc),d3              ; get current bytes in buffer
  1822.      ;
  1823.      ;      If we don't have enough bytes to satisfy the request,
  1824.      ;      set the length to the number of bytes we do have.
  1825.      ;
  1826.      cmp.l      d2,d3                   ; enuf to satisfy request?
  1827.      bge.b      15$                      ; yep, so branch
  1828.      move.l   d3,d2                   ; # to copy = # in buffer
  1829.      bra.b      16$                      ; branch to loop entry
  1830.      ;
  1831.      ;      Start of copy loop.
  1832.      ;
  1833.      cnop 0,4 ; align for 020+
  1834. 10$     move.l   i_BufPtr(pc),a2              ; reset bufout to start
  1835.      ;
  1836.      ;      Entry point of copy loop.
  1837.      ;
  1838. 15$     move.l   d2,d3                   ; xfer # of bytes to copy
  1839. 16$
  1840.      ;
  1841.      ;      If the copy will extend past the end of the buffer, we can
  1842.      ;      only copy the number of bytes to the end this go around.
  1843.      ;
  1844.      move.l   i_BufEnd(pc),d0              ; get ptr to end of buf
  1845.      sub.l      a2,d0                   ; calc # of bytes to end
  1846.      cmp.l      d0,d3                   ; # to copy < # to end?
  1847.      blt.b      20$                      ; yep, branch
  1848.      move.l   d0,d3                   ; get bytes to end
  1849.      ;
  1850.      ;      Registers:
  1851.      ;
  1852.      ;      A2 = pointer from which data will be copied
  1853.      ;      A3 = pointer to which data will be copied
  1854.      ;      D2 = number of bytes that need to be copied
  1855.      ;      D3 = number of bytes to copy this iteration
  1856.      ;
  1857. 20$     move.l   d3,d0                   ; get length
  1858.     IFNE EOFCODE
  1859.      btst      #SERB_EOFMODE,IO_SERFLAGS(a4)       ; EOFMODE requested?
  1860.      beq.b      30$                      ; nope, just go copy
  1861.      ;
  1862.      ;      EOFMODE was specified so copy characters 1 at a time until
  1863.      ;      we hit an EOF character, the output butter has filled, or
  1864.      ;      the input buffer has drained.
  1865.      ;
  1866.      ;
  1867.      move.l   IO_TERMARRAY(a4),d4              ; get termarry (part 1) (6)
  1868.      rol.l      #8,d4                   ; c1c2c3c0          (6)
  1869.      move.l   IO_TERMARRAY+4(a4),d5           ; get termarry (part 2) (6)
  1870.      move.l   d4,a1                   ; save d4           (2)
  1871.      rol.l      #8,d5                   ; c5c6c7c4          (6)
  1872.      ;
  1873. 21$     move.b   (a2)+,d1                  ; get byte          (5)
  1874.      ; This way the term char IS copied (if term char is not copied eofmode will fail)
  1875.      move.b   d1,(a3)+                  ; put in output buffer  (3)
  1876.      ;                          ; c0c1c2c3 c4c5c6c7
  1877.      cmp.b      d4,d1                   ; found term char? (c0) (2)
  1878.      bge.b      22$                      ; possibly, branch      (taken 6, not taken 4)
  1879.      rol.l      #8,d4                   ; c2c3c0c1          (6)
  1880.      cmp.b      d4,d1                   ; found term char? (c1) (2)
  1881.      bge.b      22$                      ; possibly, branch      (6 or 4)
  1882.      rol.l      #8,d4                   ; c3c0c1c2          (6)
  1883.      cmp.b      d4,d1                   ; found term char? (c2) (2)
  1884.      bge.b      22$                      ; possibly, branch      (6 or 4)
  1885.      rol.l      #8,d4                   ; c0c1c2c3          (6)
  1886.      cmp.b      d4,d1                   ; found term char? (c3) (2)
  1887.      bge.b      22$                      ; possibly, branch      (6 or 4)
  1888.      move.l   d5,d4                   ; get termarry (part 2) (2)
  1889.      cmp.b      d4,d1                   ; found term char? (c4) (2)
  1890.      bge.b      22$                      ; possibly, branch      (6 or 4)
  1891.      rol.l      #8,d4                   ; c6c7c4c5          (6)
  1892.      cmp.b      d4,d1                   ; found term char? (c5) (2)
  1893.      bge.b      22$                      ; possibly, branch      (6 or 4)
  1894.      rol.l      #8,d4                   ; c7c4c5c6          (6)
  1895.      cmp.b      d4,d1                   ; found term char? (c6) (2)
  1896.      bge.b      22$                      ; possibly, branch      (6 or 4)
  1897.      rol.l      #8,d4                   ; c4c5c6c7          (6)
  1898.      cmp.b      d4,d1                   ; found term char? (c7) (2)
  1899. 22$     beq.b      24$                      ; term char found?      (6 or 4)
  1900.      ;
  1901.      ;      Didn't find a term character, so continue with the copy loop
  1902.      ;
  1903. 23$     move.l   a1,d4                   ; get termarry (part 1) (2)
  1904.      subq.l   #1,d0                   ; decr length counter   (2)
  1905.      bne.b      21$                      ; continue if more      (6 or 4)
  1906.      bra.b      40$                      ; done with copy, branch (6)
  1907.      ;
  1908.      ;      We've found a termination character.
  1909.      ;
  1910.      cnop 0,4 ; align for 020+
  1911. 24$     clr.l      cr_Length-Start(a5)              ; done with request
  1912.      bra.b      50$                      ; branch
  1913.      cnop 0,4 ; align for 020+
  1914.     ENDC
  1915.      ;
  1916.      ;      EOFMODE not specified, so just do a bulk copy.
  1917.      ;
  1918.      ;      XXX POSSIBLE SPEEDUP XXX
  1919.      ;
  1920.      ;      For short copies it would be quicker to have a simple inline
  1921.      ;      loop, but what's short???  It would be different by CPU.
  1922.      ;
  1923. 30$     move.l   a3,a1                   ; where to put it
  1924.      move.l   a2,a0                   ; where to get it
  1925. ; NB: buffer size is multiple of 64bytes (not contents size)
  1926. ; most copys are 1 or 2 bytes, max copy usually seen is 256 bytes
  1927.      jsr      _LVOCopyMem(a6)              ; we use copymemquicker patch by *Art
  1928.      adda.l   d3,a2                   ; update bufout
  1929.      adda.l   d3,a3                   ; update outptr
  1930.      ;
  1931.      ;      Fall through and entered from EOFMODE loop
  1932.      ;
  1933.      ;      If the following calculation results in a value greater than
  1934.      ;      zero, then we have a buffer wrap and need to process the
  1935.      ;      remaining bytes at the beginning of the buffer.
  1936.      ;
  1937. 40$     sub.l      d3,d2                   ; calc bytes left to copy
  1938.      bgt.b      10$                      ; >0, more to copy, branch
  1939.      ;
  1940.      ;
  1941.      ;
  1942. 50$     move.l   a3,d1                   ; get outptr
  1943.      sub.l      cr_OutPtr(pc),d1              ; calc length
  1944.      move.l   a3,cr_OutPtr-Start(a5)          ; update outptr
  1945.      ;
  1946.      ;      Update output ptr and I/O request
  1947.      ;
  1948.      move.l   a2,i_BufOut-Start(a5)           ; store bufout ptr
  1949.      add.l      d1,IO_ACTUAL(a4)              ; update I/O request
  1950.      ;
  1951.      ;      Update number of bytes left in the buffer.
  1952.      ;
  1953.      sub.l      d1,i_InCnt-Start(a5)              ; calc bytes left in buffer
  1954.      ;
  1955.      ;      If the threshold becomes positive here, then, if requested,
  1956.      ;      tell the other end that it's okay to start sending more data.
  1957.      ;
  1958.      add.l      d1,i_Thresh-Start(a5)           ; calc thresh and test
  1959.      ble.b      60$                      ; <= 0, need more data, skip
  1960.      tst.l      Handshake(pc)               ; are we handshaking?
  1961.      beq.b      60$                      ; nope, skip RTS
  1962.      andi.b   #~(1<<CIAB_COMRTS),_ciabpra          ; ready to recieve more data
  1963.      ;
  1964.      ;      Set error if we've had any overruns.
  1965.      ;
  1966. 60$     tst.l      Overrun(pc)                  ; did overrun occur?
  1967.      bne.b      100$                      ; yep, branch
  1968.      ;
  1969.      ;      Calc number of bytes left to copy.  If the result is greater
  1970.      ;      than zero, then we have more to copy so return an incomplete
  1971.      ;      status.
  1972.      ;
  1973. 70$     moveq      #0,d0                   ; assume I/O incomplete
  1974.      sub.l      d1,cr_Length-Start(a5)          ; update length and test
  1975.      bgt.b      90$                      ; >0, more to do, branch
  1976.      ;
  1977.      ;      We've completed the I/O request either by copying the requested
  1978.      ;      of bytes or by finding an EOFMODE character, so return a "reply"
  1979.      ;      status.
  1980.      ;
  1981.      moveq      #1,d0                   ; indicate reply
  1982.      ;
  1983.      ;      Restore and exit
  1984.      ;
  1985. 90$     move.l   (sp)+,d2                  ; restore registers
  1986.      move.l   (sp)+,d3                  ; restore registers
  1987.      move.l   (sp)+,d4                  ; restore registers
  1988.      move.l   (sp)+,d5                  ; restore registers
  1989.      move.l   (sp)+,a1                  ; restore registers
  1990.      move.l   (sp)+,a2                  ; restore registers
  1991.      move.l   (sp)+,a3                  ; restore registers
  1992.      move.l   (sp)+,a4                  ; restore registers
  1993.      move.l   (sp)+,a5                  ; restore registers
  1994.      rts                          ; return (status in D0)
  1995.      cnop 0,4 ; align for 020+
  1996. 100$     clr.l      Overrun-Start(a5)              ; reset overrun flag
  1997.      move.b   #SerErr_LineErr,IO_ERROR(a4)          ; set error code
  1998.      bra.b      70$
  1999.      ;
  2000.      ;      Align data
  2001.      ;
  2002.      CNOP      0,4
  2003.      ;
  2004.      ;
  2005.      ;
  2006. Init:
  2007.      DC.L      sizeof_Base8n1
  2008.      DC.L      funcTab
  2009.      DC.L      dataTab
  2010.      DC.L      InitRoutine
  2011.      ;
  2012.      ;
  2013.      ;
  2014. funcTab:
  2015.      DC.W      -1
  2016.      DC.W      dev_Open-funcTab
  2017.      DC.W      dev_Close-funcTab
  2018.      DC.W      dev_Expunge-funcTab
  2019.      DC.W      dev_Null-funcTab
  2020.      DC.W      dev_BeginIO-funcTab
  2021.      DC.W      dev_AbortIO-funcTab
  2022.      DC.W      -1
  2023.      ;
  2024.      ;
  2025.      ;
  2026. dataTab:
  2027.      INITBYTE LN_TYPE,NT_DEVICE
  2028.      INITLONG LN_NAME,Name
  2029.      INITBYTE LIB_FLAGS,LIBF_SUMUSED|LIBF_CHANGED
  2030.      INITWORD LIB_VERSION,VERSION
  2031.      INITWORD LIB_REVISION,REVISION
  2032.      INITLONG LIB_IDSTRING,IdString
  2033.      DC.W      0
  2034.      ;
  2035.      ;      String Constants
  2036.      ;
  2037. miscresource:
  2038.      DC.B      "misc.resource",0
  2039. timerdevice:
  2040.      DC.B      "timer.device",0
  2041. intuitlib:
  2042.      DC.B      "intuition.library",0
  2043. Name:
  2044.      DC.B      "8n1.device",0
  2045. IdString:
  2046.      VSTRING
  2047.      ;
  2048.      ;      End of checksummed area.  (Realigns data too!)
  2049.      ;
  2050. ENDTag:
  2051.      CNOP      0,4
  2052.      ;
  2053.      ;      Global SysBase (Use instead of _AbsExecBase for speed)
  2054.      ;
  2055. SysBase:
  2056.      DC.L      0
  2057.      ;
  2058.      ;      Internal buffer tracking (DO NOT CHANGE THE ORDER!!!!)
  2059.      ;
  2060. i_BufPtr:
  2061.      DC.L      0
  2062. i_BufIn:
  2063.      DC.L      0
  2064. i_BufOut:
  2065.      DC.L      0
  2066. i_BufEnd:
  2067.      DC.L      0
  2068. i_InCnt:
  2069.      DC.L      0
  2070. i_Thresh:
  2071.      DC.L      0
  2072.      ;
  2073.      ;      Used while processing a read request.
  2074.      ;
  2075. cr_IOReq:
  2076.      DC.L      0
  2077. cr_OutPtr:
  2078.      DC.L      0
  2079. cr_Length:
  2080.      DC.L      0
  2081.      ;
  2082.      ;      List head for read requests
  2083.      ;
  2084. readQ:
  2085.      DC.L      readQ+MLH_TAIL
  2086.      DC.L      0
  2087.      DC.L      readQ
  2088.      ;
  2089.      ;      Write control.
  2090.      ;
  2091. cw_Length:
  2092.      DC.L      0
  2093. cw_Buffer:
  2094.      DC.L      0
  2095. cw_IOReq:
  2096.      DC.L      0
  2097.      ;
  2098.      ;      List head for write requests
  2099.      ;
  2100. writeQ:
  2101.      DC.L      writeQ+MLH_TAIL
  2102.      DC.L      0
  2103.      DC.L      writeQ
  2104.      ;
  2105.      ;
  2106.      ;
  2107. timerPort:
  2108.      DC.L      0                      ; LN_SUCC
  2109.      DC.L      0                      ; LN_PRED
  2110.      DC.B      NT_MSGPORT                  ; LN_TYPE
  2111.      DC.B      0                      ; LN_PRI
  2112.      DC.L      0                      ; LN_NAME
  2113.      DC.B      3                      ; MP_FLAGS (undoc'ed)
  2114.      DC.B      0                      ; MP_SIGBIT
  2115.      DC.L      timerRtn                  ; MP_SIGTASK
  2116.      DC.L      timerPort+MP_MSGLIST+LH_TAIL          ; LH_HEAD
  2117.      DC.L      0                      ; LH_TAIL
  2118.      DC.L      timerPort+MP_MSGLIST              ; LH_TAILPRED
  2119.      DC.B      0                      ; LH_TYPE
  2120.      DC.B      0                      ; LH_pad
  2121.      DC.W      0                      ; long align
  2122.      ;
  2123.      ;
  2124.      ;
  2125. timerReq:
  2126.      DC.L      0                      ; LN_SUCC
  2127.      DC.L      0                      ; LN_PRED
  2128.      DC.B      NT_MESSAGE                  ; LN_TYPE
  2129.      DC.B      0                      ; LN_PRI
  2130.      DC.L      0                      ; LN_NAME
  2131.      DC.L      timerPort                  ; MN_REPLYPORT
  2132.      DC.W      IOTV_SIZE                  ; MN_LENGTH
  2133.      DC.L      0                      ; IO_DEVICE
  2134.      DC.L      0                      ; IO_UNIT
  2135.      DC.W      TR_ADDREQUEST               ; IO_COMMAND
  2136.      DC.B      0                      ; IO_FLAGS
  2137.      DC.B      0                      ; IO_ERROR
  2138.      DC.L      0                      ; TV_SECS
  2139.      DC.L      0                      ; TV_MICROS
  2140.      ;
  2141.      ;
  2142.      ;
  2143. VBInterrupt:
  2144.      DC.L      0                      ; LN_SUCC
  2145.      DC.L      0                      ; LN_PRED
  2146.      DC.B      NT_INTERRUPT                  ; LN_TYPE
  2147.      DC.B      0                      ; LN_PRI
  2148.      DC.L      Name                      ; LN_NAME
  2149.      DC.L      readQ                   ; IS_DATA
  2150.      DC.L      level2                  ; IS_CODE
  2151.      ;
  2152.      ;      Global flags
  2153.      ;
  2154.      CNOP 0,4
  2155. Overrun:
  2156.      DC.L      0
  2157. Handshake:
  2158.      DC.L      1
  2159. disableRead:
  2160.      DC.L      -1
  2161. cmdlist:
  2162.      dc.w      CMD_RESET
  2163.      dc.w      CMD_READ
  2164.      dc.w      CMD_WRITE
  2165.      dc.w      CMD_CLEAR
  2166.      dc.w      CMD_FLUSH
  2167.      dc.w      SDCMD_QUERY
  2168.      dc.w      SDCMD_BREAK
  2169.      dc.w      SDCMD_SETPARAMS
  2170.      dc.w      NSCMD_DEVICEQUERY
  2171.      dc.w      0
  2172.      ;
  2173.      ;
  2174.      ;
  2175.      END
  2176.  
  2177.